基于epoll的多线程网络服务程序设计——C语言

采用C语言设计了一个基于epoll的多线程网络服务程序。每个线程都有一个epoll来捕获处于这个线程的socket事件。当子线程数量为0,即只有一个线程,则网络监听服务与socket消息处理处于同一个epoll。当子线程数量大于0时,主线程监听socket连接,当有新的连接到来时将其加入到活跃socket数量最小的子线程的epoll中。

server.h

#ifndef EPOLL_C_SERVER_H
#define EPOLL_C_SERVER_H#include <stdio.h>
#include <stdlib.h>
#include <string.h>#include <unistd.h>
#include <errno.h>
#include <sys/epoll.h>
#include <pthread.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>#define RESULT_OK 0
#define RESULT_ERROR -1/**************************************************************************
* Function    : *MSG_HANDLE
* Input       : socket_fd --> socket文件描述符
*             : arg --> void* 参数
* Output      :
* Return      : 1 处理成功,继续等待下次消息;0 处理完毕完毕该连接;-1 异常错误发生
* Description : 消息处理函数指针
****************************************************************************/
typedef int (*MSG_HANDLE)(int socket_fd,void* arg) ;  typedef struct
{int epoll_fd;pthread_t thd_fd;//消息处理函数,各个线程会调用该函数进行消息处理MSG_HANDLE data_func;//一个线程里面的有效socket数量unsigned int active_conection_cnt; //线程互斥锁,用于实时更新有效socket数量pthread_mutex_t thd_mutex;
}socket_thd_struct;   //表示处理socket的子线程typedef struct
{int epoll_fd;unsigned short ip_port;//消息处理函数,当只有一个线程时,会调用该函数进行消息处理MSG_HANDLE data_func;//子线程数量,可以为0,为0表示server与socket处理处于同一个线程unsigned int socket_pthread_count; //子线程结构体指针socket_thd_struct* socket_thd;   }server_struct;  //一个网络服务结构体/**************************************************************************
* Function    : initServerStruct
* Input       : param_port --> 服务端口号
*             : param_thd_count --> 子线程数量,用于处理连接的client
*             : param_handle --> socket数据处理函数指针
* Output      :
* Return      : 初始化好的server结构体
* Description : 初始化server结构体
****************************************************************************/
server_struct* initServerStruct(unsigned short param_port,unsigned int param_thd_count,MSG_HANDLE param_handle);/**************************************************************************
* Function    : serverRun
* Input       : param_server --> server服务结构体参数
* Output      :
* Return      :RESULT_OK(0):执行成功;RESULT_ERROR(-1):执行失败
* Description : 运行网络服务,监听服务端口
****************************************************************************/
int serverRun(server_struct *param_server);#endif //EPOLL_C_SERVER_H

server.c

#include "server.h"static void* socketPthreadRun(void* arg)
{socket_thd_struct* pa_sock_st=(socket_thd_struct*)arg;int active_counts=0;struct epoll_event ev;struct epoll_event events[5];int ret=0;while(1){//等待读写事件的到来active_counts=epoll_wait(pa_sock_st->epoll_fd,events,5,-1);fprintf(stdout,"active count:%d\n",active_counts);int index=0;for(index=0;index<active_counts;index++){if(events[index].events&EPOLLERR) //发生异常错误{fprintf(stderr,"error happened:errno(%d)-%s\n",errno,strerror(errno));epoll_ctl(pa_sock_st->epoll_fd,EPOLL_CTL_DEL,events[index].data.fd,NULL);close(events[index].data.fd);pthread_mutex_lock(&(pa_sock_st->thd_mutex));pa_sock_st->active_conection_cnt--;pthread_mutex_unlock(&(pa_sock_st->thd_mutex));}else if(events[index].events&EPOLLRDHUP) //对端异常关闭连接{fprintf(stdout,"client close this socket\n");epoll_ctl(pa_sock_st->epoll_fd,EPOLL_CTL_DEL,events[index].data.fd,NULL);close(events[index].data.fd);pthread_mutex_lock(&(pa_sock_st->thd_mutex));pa_sock_st->active_conection_cnt--;pthread_mutex_unlock(&(pa_sock_st->thd_mutex));}else if(events[index].events&EPOLLIN) //读事件到来,进行消息处理{ret=pa_sock_st->data_func(events[index].data.fd,NULL);if(ret==-1){fprintf(stderr,"client socket exception happened\n");epoll_ctl(pa_sock_st->epoll_fd,EPOLL_CTL_DEL,events[index].data.fd,NULL);close(events[index].data.fd);pthread_mutex_lock(&(pa_sock_st->thd_mutex));pa_sock_st->active_conection_cnt--;pthread_mutex_unlock(&(pa_sock_st->thd_mutex));}if(ret==0){fprintf(stdout,"client close this socket\n");epoll_ctl(pa_sock_st->epoll_fd,EPOLL_CTL_DEL,events[index].data.fd,NULL);close(events[index].data.fd);pthread_mutex_lock(&(pa_sock_st->thd_mutex));pa_sock_st->active_conection_cnt--;pthread_mutex_unlock(&(pa_sock_st->thd_mutex));}else if(ret==1){}}}}pthread_exit(NULL);
}server_struct* initServerStruct(unsigned short param_port,unsigned int param_thd_count,MSG_HANDLE param_handle)
{server_struct* serv_st=(server_struct*)malloc(sizeof(server_struct));serv_st->ip_port=param_port;serv_st->data_func=param_handle;serv_st->epoll_fd=epoll_create(256);serv_st->socket_pthread_count=param_thd_count;serv_st->socket_thd=NULL;if(serv_st->socket_pthread_count>0){fprintf(stdout,"create client socket sub thread\n");serv_st->socket_thd=(socket_thd_struct*)malloc(sizeof(socket_thd_struct)*serv_st->socket_pthread_count);int index=0;for(index=0;index<serv_st->socket_pthread_count;index++){serv_st->socket_thd[index].epoll_fd=epoll_create(256);serv_st->socket_thd[index].data_func=param_handle;serv_st->socket_thd[index].active_conection_cnt=0;serv_st->socket_thd[index].thd_fd=0;//创建子线程pthread_create(&(serv_st->socket_thd[index].thd_fd),NULL,socketPthreadRun,(void*)&(serv_st->socket_thd[index]));//初始化线程互斥锁pthread_mutex_init(&(serv_st->socket_thd[index].thd_mutex),NULL);}}return serv_st;
}int serverRun(server_struct *param_server)
{int ret=RESULT_OK;int server_socket=0;struct sockaddr_in server_addr;bzero(&server_addr,sizeof(server_addr));struct epoll_event ev;struct epoll_event events[5];int active_count=0;int index=0;int new_socket=0;struct sockaddr_in client_info;socklen_t client_info_len=0;server_addr.sin_family=AF_INET;server_addr.sin_addr.s_addr=htons(INADDR_ANY);server_addr.sin_port=htons(param_server->ip_port);server_socket=socket(PF_INET,SOCK_STREAM,0);if(server_socket<0){fprintf(stderr,"create socket error:errno(%d)-%s\n",errno,strerror(errno));return RESULT_ERROR;}fprintf(stdout,"create server socket ssuccessful\n");param_server->epoll_fd=epoll_create(256);ev.data.fd=server_socket;ev.events=EPOLLIN|EPOLLET;if(epoll_ctl(param_server->epoll_fd,EPOLL_CTL_ADD,server_socket,&ev)!=0){fprintf(stderr,"server socket add to epoll error:errno(%d)-%s\n",errno,strerror(errno));return RESULT_ERROR;}fprintf(stdout,"server socket add to epoll successful\n");if(bind(server_socket,(struct sockaddr*)&server_addr,sizeof(server_addr))!=0){fprintf(stderr,"server bind failed:errno(%d)-%s\n",errno,strerror(errno));return RESULT_ERROR;}fprintf(stdout,"server socket bind successful\n");if(listen(server_socket,param_server->ip_port)!=0){fprintf(stderr,"server listen failed:errno(%d)-%s\n",errno,strerror(errno));return RESULT_ERROR;}fprintf(stdout,"server socket listen successful\n");while(1){active_count=epoll_wait(param_server->epoll_fd,events,5,-1);fprintf(stdout,"active count:%d\n",active_count);for(index=0;index<active_count;index++){if(events[index].data.fd==server_socket) //新连接过来{fprintf(stdout,"new socket comming\n");client_info_len=sizeof(client_info);new_socket=accept(server_socket,(struct sockaddr*)&client_info,&client_info_len);if(new_socket<0){fprintf(stderr,"server accept failed:errno(%d)-%s\n",errno,strerror(errno));continue;}fprintf(stdout,"new socket:%d.%d.%d.%d:%d-->connected\n",((unsigned char*)&(client_info.sin_addr))[0],((unsigned char*)&(client_info.sin_addr))[1],((unsigned char*)&(client_info.sin_addr))[2],((unsigned char*)&(client_info.sin_addr))[3],client_info.sin_port);ev.data.fd=new_socket;ev.events=EPOLLIN|EPOLLERR|EPOLLRDHUP;if(param_server->socket_pthread_count==0){epoll_ctl(param_server->epoll_fd,EPOLL_CTL_ADD,new_socket,&ev);}else{int tmp_index=0;int mix_cnt_thread_id=0;unsigned int act_cnts=0;for(tmp_index=0;tmp_index<param_server->socket_pthread_count;tmp_index++){pthread_mutex_lock(&(param_server->socket_thd[tmp_index].thd_mutex));act_cnts=param_server->socket_thd[tmp_index].active_conection_cnt;pthread_mutex_unlock(&(param_server->socket_thd[tmp_index].thd_mutex));if(mix_cnt_thread_id>act_cnts){mix_cnt_thread_id=tmp_index;}}epoll_ctl(param_server->socket_thd[mix_cnt_thread_id].epoll_fd,EPOLL_CTL_ADD,new_socket,&ev);pthread_mutex_lock(&(param_server->socket_thd[mix_cnt_thread_id].thd_mutex));param_server->socket_thd[mix_cnt_thread_id].active_conection_cnt++;pthread_mutex_unlock(&(param_server->socket_thd[mix_cnt_thread_id].thd_mutex));}fprintf(stdout,"add new client socket to epoll\n");}else if(events[index].events&EPOLLERR || events[index].events&EPOLLRDHUP) //对端关闭连接{fprintf(stdout,"client close this socket\n");epoll_ctl(param_server->epoll_fd,EPOLL_CTL_DEL,events[index].data.fd,NULL);close(events[index].data.fd);}else if(events[index].events&EPOLLIN) //读事件到来,进行消息处理{fprintf(stdout,"begin recv client data\n");ret=param_server->data_func(events[index].data.fd,NULL);if(ret==-1){fprintf(stderr,"client socket exception happened\n");epoll_ctl(param_server->epoll_fd,EPOLL_CTL_DEL,events[index].data.fd,NULL);close(events[index].data.fd);}if(ret==0){fprintf(stdout,"client close this socket\n");epoll_ctl(param_server->epoll_fd,EPOLL_CTL_DEL,events[index].data.fd,NULL);close(events[index].data.fd);}else if(ret==1){}}}}close(server_socket);return RESULT_OK;
}

基于epoll的多线程网络服务程序设计——C语言相关推荐

  1. Go 开源说第十八期预告:基于 Reactor 模式开发网络服务——gnet

    点击蓝字 关注我们 写在前面 GoCN开源说是GoCN推出的一档分享Go开源好项目的直播栏目,通过开源说希望能够帮助到开源作者们实现以下目标: 第一是去推广他们的开源项目 第二说说背后的设计原理和理念 ...

  2. 学习C++项目—— 搭建多线程网络服务框架,性能测试(并发性能测试,业务性能测试,客户端响应时间测试,网络带宽测试)

    学习计算机网络编程 一.思路和学习方法   本文学习于:C语言技术网(www.freecplus.net),在 b 站学习于 C 语言技术网,并加以自己的一些理解和复现,如有侵权会删除.   接下来对 ...

  3. A10 : 如何通过NFV-MANO解决方案,安全快速地部署基于软件的移动网络服务

    移动服务提供商(SP)正在快速由4G向5G演进.但由于4G网络里的部署了大量来自不同厂商的.不同品牌的硬件设备,移动运营商部署网络服务时,会遇到不灵活.耗时长.不易管理的难题. 于是,移动服务提供商们 ...

  4. 回顾2007:新兴网络服务汇总(完整篇)

    原贴:http://blog.bsdos.cn/archives/1191 上次在回顾2007:我最爱的互联网服务及本地软件一文中,只是列出了我日常用得最多的几个服务,但事实上在整个2007年我曾介绍 ...

  5. 2007年新兴网络服务

    Web2.0也喊了2年多了,人们也越来越习惯了SaaS的形式.现在让我们回顾下在2007年新兴网络服务.也许有些你正在使用,有些还全然不知.总之他是会给你的网络工作.生活带来一些便捷-- 一月份新兴服 ...

  6. ZT: 回顾2007:新兴网络服务汇总(完整篇)

    注:此系列文章"回顾2007:新兴网络服务汇总"原文发布于WappBlog上,共12篇 -1月 2月 3月 4月 5月 6月 7月 8月 9月 10月 11月 12月. 上次在回顾 ...

  7. as 不显示gradle视图_Python构建RESTful网络服务[Django篇:基于类视图的API]

    系列文章介绍 本系列文章将详细介绍将Django官方引导教程中的投票项目改写为RESTful网络服务.Django官方教程地址https://docs.djangoproject.com/zh-han ...

  8. 算力网络中基于算力标识的算力服务需求匹配

    摘要 [目的]随着数字经济发展不断深入与新型行业应用场景的不断涌现,全社会算力需求持续增长,"东数西算"等国家战略的逐步落地为以算力网络为代表的新型网络技术的发展带来强劲的驱动力. ...

  9. 基于python的网络爬虫编程_基于Python的网络爬虫程序设计

    程序设计 ●Program Design 基于 Python的网络爬虫程序设计 网络 信 息量 的迅 猛 增 长,对 如何从海量的信息中准确的搜索 到用户需要的信息提 出了极大的 挑战.网络爬 虫具有 ...

  10. Android基于NSD实现网络服务发现功能

    一. 简介 网络服务发现:一般是指通过此功能,在局域网内来发现同样支持此功能的设备,并跟其他设备建立连接. Android 提供了一个网络服务发现(NSD),可让应用访问其他设备在本地网路上提供的服务 ...

最新文章

  1. 云计算和大数据时代网络技术揭秘(八)数据中心存储FCoE
  2. B/S软件超越C/S软件的优势在哪里?
  3. Netty 和 RPC 框架线程模型分析
  4. 英语发音规则---发/i:/的字母及字母组合
  5. 【若依(ruoyi)】表格图片预览功能图片超宽、超高问题
  6. 计算机组成与维修考试试题,期末考试试题计算机组成与维修.doc
  7. 编程题: 将一个矩阵(二维数组)顺时针旋转90度
  8. php两个数组融合,php合并两个数组的方式有哪些
  9. 菜鸟python_手把手教你,菜鸟也能用Python写一个2048游戏
  10. 7007.svg用法
  11. 《推荐系统笔记(六)》svd在推荐系统中的应用推广(FunkSVD,BiasSVD以及SVD++)及简单实战(surprise库)
  12. 【SQL】字符串去空格解决方法
  13. python字符串去掉特殊符号_python去特殊字符_python 去字符串中特殊符号 - CSDN
  14. Js学习之拖拉事件(drag)
  15. Centos迁移旧硬盘的数据
  16. 关于 Bandizip 每次解压都催你更新
  17. python调用DLL/EXE文件截屏的比较
  18. idcard detection using opencv
  19. c语言自动填表chrome网页,Form Filler:自动填写表单
  20. CMUSphinx免费离线语音识别开源库教程iOS开发

热门文章

  1. css 去除文本框按钮发光圈,tips之CSS动态实现文本框清除按钮的隐藏与显示
  2. 软件设计师——大题2——数据库设计
  3. 功能安全——安全计划
  4. 人工神经网络心得体会_神经网络,人工智能这块怎么入门?
  5. 项目经理跨部门沟通的6个原则
  6. 【大虾送书第十二期】MLOps快速成为机器学习生产落地中不可或缺的关键能力
  7. 软考缺考会有什么影响?你知道吗?
  8. 谈人工智能和数据治理
  9. 深度学习数据自动编码器_我对从开放大学学习编码以进行数据分析的评论
  10. 英语口语exam5(culture)