// epoll2.cpp : 定义控制台应用程序的入口点。
//#include <stdio.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <pthread.h>//stl head#include <ext/hash_map> //包含hash_map 的头文件//#include <map> //stl的mapusing namespace std; //std 命名空间using namespace __gnu_cxx; //而hash_map是在__gnu_cxx的命名空间里的int init_thread_pool(int threadNum);
void *epoll_loop(void* para);
void *check_connect_timeout(void* para);struct sockStruct
{time_t time;unsigned int* recvBuf;
};//hash-map//hash_map<int, unsigned int>        sock_map;hash_map<int, sockStruct>        sock_map;
#define MAXRECVBUF 4096
#define MAXBUF MAXRECVBUF+10int fd_Setnonblocking(int fd)
{int op;op=fcntl(fd,F_GETFL,0);fcntl(fd,F_SETFL,op|O_NONBLOCK);return op;
}void on_sigint(int signal)
{exit(0);
}/*
handle_message - 处理每个 socket 上的消息收发
*/
int handle_message(int new_fd)
{char buf[MAXBUF + 1];char sendbuf[MAXBUF+1];int len;/* 开始处理每个新连接上的数据收发 */bzero(buf, MAXBUF + 1);/* 接收客户端的消息 *///len = recv(new_fd, buf, MAXBUF, 0);int nRecvBuf = MAXRECVBUF; //设置为32Ksetsockopt(new_fd, SOL_SOCKET, SO_RCVBUF, ( const char* )&nRecvBuf, sizeof(int));len=recv(new_fd,&buf, MAXBUF,0);//--------------------------------------------------------------------------------------------//这块为了使用ab测试char bufSend[1000] = {0};sprintf(bufSend,"HTTP/1.0 200 OK\r\nContent-type: text/plain\r\n\r\n%s","Hello world!\n");send(new_fd,bufSend,strlen(buf),0);//--------------------------------------------------------------------------------------------if (len > 0){//printf ("%d接收消息成功:'%s',共%d个字节的数据\n", new_fd, buf, len);//hash-maphash_map<int, sockStruct>::iterator it_find;it_find = sock_map.find(new_fd);if(it_find == sock_map.end()){//新的网络连接,申请新的接收缓冲区,并放入map中//printf("new socket %d\n", new_fd);sockStruct newSockStruct;newSockStruct.time = time((time_t*)0);newSockStruct.recvBuf = (unsigned int*)malloc(1000);memset(newSockStruct.recvBuf, 0, 1000);strcat((char*)newSockStruct.recvBuf, buf);sock_map.insert(pair<int,sockStruct>(new_fd, newSockStruct));}else{//网络连接已经存在,找到对应的数据缓冲区,将接收到的数据拼接到数据缓冲区中//printf("socket %d exist!\n", it_find->first);(it_find->second).time = time((time_t*)0);                //时间更改char* bufSockMap = (char*)(it_find->second).recvBuf;    //数据存储strcat(bufSockMap, buf);//printf("bufSockMap:%s\n", bufSockMap);}}else {if (len < 0)printf ("消息接收失败!错误代码是%d,错误信息是'%s'\n",errno, strerror(errno));else {//将socket从map中移除/*hash_map<int, sockStruct>::iterator it_find;it_find = sock_map.find(new_fd);sock_map.erase(it_find);*/printf("client %d quit!\n",new_fd);}//close(new_fd);return -1;}/* 处理每个新连接上的数据收发结束 *///关闭socket的时候,要释放接收缓冲区。hash_map<int, sockStruct>::iterator it_find;it_find = sock_map.find(new_fd);free((it_find->second).recvBuf);sock_map.erase(it_find);close(new_fd);return len;
}int listenfd;
int sock_op=1;
struct sockaddr_in address;
struct epoll_event event0;
struct epoll_event events[1024];
int epfd;
int n;
int i;
char buf[512];
int off;
int result;
char *p;int main(int argc,char* argv[])
{init_thread_pool(1);signal(SIGPIPE,SIG_IGN);signal(SIGCHLD,SIG_IGN);signal(SIGINT,&on_sigint);listenfd=socket(AF_INET,SOCK_STREAM,0);setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&sock_op,sizeof(sock_op));memset(&address,0,sizeof(address));address.sin_addr.s_addr=htonl(INADDR_ANY);address.sin_port=htons(8006);bind(listenfd,(struct sockaddr*)&address,sizeof(address));listen(listenfd,1024);fd_Setnonblocking(listenfd);epfd=epoll_create(65535);memset(&event0,0,sizeof(event0));event0.data.fd=listenfd;event0.events=EPOLLIN|EPOLLET;epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&event0);while(1){sleep(1000);}return 0;
}/*************************************************
* Function: * init_thread_pool
* Description: * 初始化线程
* Input: * threadNum:用于处理epoll的线程数
* Output: *
* Others: * 此函数为静态static函数,
*************************************************/
int init_thread_pool(int threadNum)
{int i,ret;pthread_t threadId;//初始化epoll线程池for ( i = 0; i < threadNum; i++){ret = pthread_create(&threadId, 0, epoll_loop, (void *)0);if (ret != 0){printf("pthread create failed!\n");return(-1);}}ret = pthread_create(&threadId, 0, check_connect_timeout, (void *)0);return(0);
}
/*************************************************
* Function: * epoll_loop
* Description: * epoll检测循环
* Input: *
* Output: *
* Others: *
*************************************************/
static int count111 = 0;
static time_t oldtime = 0, nowtime = 0;
void *epoll_loop(void* para)
{while(1){n=epoll_wait(epfd,events,4096,-1);//printf("n = %d\n", n);if(n>0){for(i=0;i<n;++i){if(events[i].data.fd==listenfd){while(1){event0.data.fd=accept(listenfd,NULL,NULL);if(event0.data.fd>0){fd_Setnonblocking(event0.data.fd);event0.events=EPOLLIN|EPOLLET;epoll_ctl(epfd,EPOLL_CTL_ADD,event0.data.fd,&event0);}else{if(errno==EAGAIN)break;}}}else{if(events[i].events&EPOLLIN){//handle_message(events[i].data.fd);char recvBuf[1024] = {0};int ret = 999;int rs = 1;while(rs){ret = recv(events[n].data.fd,recvBuf,1024,0);// 接受客户端消息if(ret < 0){//由于是非阻塞的模式,所以当errno为EAGAIN时,表示当前缓冲区已无数据可//读在这里就当作是该次事件已处理过。if(errno == EAGAIN){printf("EAGAIN\n");break;}else{printf("recv error!\n");epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, &event0);close(events[i].data.fd);break;}}else if(ret == 0){// 这里表示对端的socket已正常关闭.rs = 0;}if(ret == sizeof(recvBuf))rs = 1; // 需要再次读取elsers = 0;}if(ret>0){count111 ++;struct tm *today;time_t ltime;time( &nowtime );if(nowtime != oldtime){printf("%d\n", count111);oldtime = nowtime;count111 = 0;}char buf[1000] = {0};sprintf(buf,"HTTP/1.0 200 OK\r\nContent-type: text/plain\r\n\r\n%s","Hello world!\n");send(events[i].data.fd,buf,strlen(buf),0);//    CGelsServer Gelsserver;//    Gelsserver.handle_message(events[i].data.fd);}epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, &event0);close(events[i].data.fd);}else if(events[i].events&EPOLLOUT){sprintf(buf,"HTTP/1.0 200 OK\r\nContent-type: text/plain\r\n\r\n%s","Hello world!\n");send(events[i].data.fd,buf,strlen(buf),0);/*if(p!=NULL){free(p);p=NULL;}*/close(events[i].data.fd);}else{close(events[i].data.fd);}}}}}}
/*************************************************
* Function: * check_connect_timeout
* Description: * 检测长时间没反应的网络连接,并关闭删除
* Input: *
* Output: *
* Others: *
*************************************************/
void *check_connect_timeout(void* para)
{hash_map<int, sockStruct>::iterator it_find;for(it_find = sock_map.begin(); it_find!=sock_map.end(); ++it_find){if( time((time_t*)0) - (it_find->second).time > 120){                //时间更改free((it_find->second).recvBuf);sock_map.erase(it_find);close(it_find->first);}}}

代码是在vs2017下建立linux工程编译的,编译的时候加入一个pthread多线程的库

网络编程五种IO模型之epoll模型相关推荐

  1. 网络编程五种IO模型的形象比喻(老陈收信)

    网摘录如下比喻,实在生动贴切..... select模型  WSAAsyncSelect模型  WSAEventSelect模型  Overlapped I/O 事件通知模型  Overlapped ...

  2. 网络编程五种IO模型之poll模型

    // poll_impl.cpp : 定义控制台应用程序的入口点. //#include "stdafx.h"#include <unistd.h> #include ...

  3. 说说基于网络的五种IO模型

    # django不是一个异步框架 # tornado是异步的web框架# 处理每秒大量的请求# 个人理解的IO:就是应用层与内核驱动层的交互,这个过程无论从应用层到内核中,还是驱动层等待硬件层的数据, ...

  4. Linux网络编程 五种I/O 模式及select、epoll方法的理解

    近期一次面试机会让我觉得有很多地方理解可能不到位,翻翻谷歌的资料加深对一些技术的理解 五种I/O 模式: [1] 阻塞 I/O (Linux下的I/O操作默认是阻塞I/O,即open和socket创建 ...

  5. 0729------Linux网络编程----------使用 select 、poll 和 epoll 模型 编写客户端程序

    1.select 模型 1.1 select 函数原型如下,其中 nfds 表示的描述符的最大值加1(因为这里是左闭右开区间),中间三个参数分别表示要监听的不同类型描述符的集合,timeout用来表示 ...

  6. 你应该知道的五种IO模型

    点击上方蓝色字体,选择"设为星标" 优质文章,及时送达 写在前面 linux操作系统包含了五种IO模型,各种上层编程语言或者网络编程框架的上层实现都是基于操作系统的这些IO实现来实 ...

  7. Linux五种IO模型性能分析

    转载:http://blog.csdn.net/jay900323/article/details/18141217     Linux五种IO模型性能分析 目录(?)[-] 概念理解 Linux下的 ...

  8. Linux 下的五种 IO 模型

    Linux 下的五种 IO 模型 来源:decaywood's Blog 概念说明 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2 ...

  9. 聊聊 Linux 中的五种 IO 模型

    聊聊 Linux 中的五种 IO 模型 2016/04/21 · IT技术 · 8 评论 · iO, 同步, 异步, 阻塞, 非阻塞 分享到:0 本文作者: 伯乐在线 - 陶邦仁 .未经作者许可,禁止 ...

最新文章

  1. 高并发服务优化篇:从RPC预热转发看服务端性能调优
  2. 深入浅析zookeeper的一致性模型及其实现
  3. composer安装fxp插件时候提示内存不足且没有交换空间的解决办法
  4. 减小程序规模!稀疏数组Sparsearray,数据结构二维数组与稀疏数组转换,Java实现
  5. docker 运行jar exit_使用Dockerfile为SpringBoot应用构建Docker镜像
  6. 256qam调制星座图_科普:5G是怎么调制的?
  7. CSS代码属性大全(HTML)
  8. jsonrpc php使用,Json-RPC 的 PHP 扩展 php-JsonRPC
  9. VLAN(虚拟局域网)
  10. Windows/Linux/MacOS下VMware Workstation Pro/Vmware Fusion虚拟机的安装使用,Vmware Tools 的安装,Vmware使用技巧与故障排除。
  11. 微积分小糊涂,国庆节大快乐!
  12. ELK企业内部日志分析系统(elasticsearch/logstash/beats/kibana)centos7详解
  13. JAVA基于JSP的在线人才招聘求职系统【数据库设计、论文、源码、开题报告】
  14. Word——加了项目符号后,第二行就与第一行对不齐的一种解决方法
  15. Web基础技术开发设计规范
  16. 英伟达A100 Tensor Core GPU架构深度讲解
  17. java导出excel问题记录
  18. 自学电脑专业技术可以考证吗
  19. 【Netty 】Netty 是什么?能做什么?
  20. 行业凛冬,Android开发怎样准备一场完美的面试?

热门文章

  1. linux 命令last -x,Linux常用命令last的使用方法详解
  2. mysql5.7.1.9二进制安装_mysql 5.7.9 linux二进制安装
  3. Spring框架基于AspectJ的AOP开发规范和步骤
  4. Visual Studio查找搜索类和方法的快捷方法
  5. Log4j输出格式控制--log4j的PatternLayout参数含义
  6. 从零开始学习jQuery (九) jQuery工具函数
  7. MIT自然语言处理第一讲:简介和概述(第三部分)
  8. 为什么C++(感谢waterwalk翻译)
  9. MATLAB工作环境
  10. 【 Thread】创建线程的2种方法