epoll编程-I/O多路复用

本文深入讲解了Linux下的Epoll机制,包括Epoll的基本概念、相关函数介绍、工作模式对比及其实现步骤。并通过一个简单的聊天室程序实例展示了Epoll的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文章来源:http://blog.youkuaiyun.com/oxp7085915/article/details/43196115

Epoll定义

epollLinux内核为处理大批句柄而作改进的poll,是Linux下多路复用IO接口select/poll的增强版本,它能显著的减少程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。因为它会复用文件描述符集合来传递结果而不是迫使开发者每次等待事件之前都必须重新准备要被侦听的文件描述符集合,另一个原因就是获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入Ready队列的描述符集合。然后根据这个集合进行相应的数据处理。

Epoll相关函数

#include <sys/epoll.h>

int epoll_create(int size);

int epoll_ctl(int epfd, int op,int fd,struct epoll_event *event);

int epoll_wait(int epfd,struct epoll_event*event,int maxevents,int timeout);

Epoll工作模式

Epoll用于两种工作模式-水平触发(Level Triggered)和边缘触发(Edge Triggered).

水平触发(Level Triggered),是缺省的工作方式,并且同时支持 block non-block socket。在这种做法中,内核告诉你一个文件描述符是否就绪了,然后你可以对这个就绪的fd进行IO操作。如果你不作任何操作,内核还是会继续通知你的,所以,这种模式编程出错误可能性要小一点。传统的select\poll都是这种模型的代表。

边缘触发(Edge Triggered).是高速工作方式,只支持no-block socket。在这种模式下,当描述符从未就绪变为就绪时,内核通过epoll告诉你。然后它会假设你知道文件描述符已经就绪,并且不会再为那个文件描述符发送更多的就绪通知,等到下次有新的数据进来的时候才会再次出发就绪事件。

区别LT事件不会丢弃,而是只要读buffer里面有数据可以让用户读取,则不断的通知你。而ET则只在事件发生之时通知。

Epoll使用步骤

1、使用epoll_create函数创建epoll句柄

在内核版本2.6.8以后epoll_create函数中的size就不被使用,但是需要这个参数大于0

2、事件注册

int epoll_ctl(int epfd, int op ,int fd,struct epoll_event *event);

参数解析:

Epfd:epoll_create所拿到的句柄

op:表示要在epfd上进行的操作,其用三个宏来表示

           EPOLL_CTL_ADD:注册新的fdepfd中;

           EPOLL_CTL_MOD:修改已经注册的fd的监听事件

           EPOLL_CTL_DEL: epfd中删除fd

Fd:需要监听的fd

Event:告诉内核监听事件的类型,其 struct epoll_event结构体如下所示:

typedef union epoll_data { 

    void *ptr; 

    int fd; 

    __uint32_t u32; 

    __uint64_t u64; 

} epoll_data_t; 

struct epoll_event { 

    __uint32_t events;/* Epoll events */ 

    epoll_data_t data;/* User datavariable */ 

}; 

其中包含两部分:

事件类型(events),可以使用以下的几个宏:

EPOLLIN 表示对应的文件描述符可以读(包括对端SOCKET正常关闭);

EPOLLOUT:表示对应的文件描述符可以写;

EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);

EPOLLERR:表示对应的文件描述符发生错误;

EPOLLHUP:表示对应的文件描述符被挂断;

EPOLLET EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。

EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里

用户数据,用户可以将相关文件描述符的的数据存放到data中。

3、等待事件产生

      int epoll_wait(int epfd,struct epoll_event *event,int maxevents,int timeout);

参数events用来从内核得到事件的集合,maxevents告之内核这个events有多大,这个maxevents的值必须大于0,参数timeout是超时时间(毫秒单位计数,0会立即返回,-1将不确定,也有说法说是永久阻塞)。该函数返回需要处理的事件数目,如返回0表示已超时。

Epoll应用举例

实现简单的聊天室程序,服务器是基于epoll模型实现。整个程序包含1个头文件和3个c文件,service.c为服务器程序,client.c为客户端程序,socket.c为socket封装好的API函数接口

service.c程序

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /*************************************************************************************************************  
  2.  * 文件名:             service.c  
  3.  * 功能:              基于TCP创建socket服务端程序 
  4.  * 作者:              edward  
  5.  * 创建时间:        2014年12月31日9:45  
  6.  * 最后修改时间:  2012年3月12日  
  7.  * 详细:              根据的socket建立TCP连接过程,创建服务程序, 
  8.                     并在服务端等待接收和处理客户端的数据, 
  9.                     并将结果输出到终端上 
  10. *************************************************************************************************************/    
  11. #include <stdio.h>  
  12. #include <stdlib.h>  
  13. #include <errno.h>  
  14. #include <string.h>  
  15. #include <sys/epoll.h>  
  16. #include <sys/types.h>   
  17. #include <sys/socket.h>  
  18. #include <netinet/in.h>  
  19. #include <poll.h>  
  20. #include <fcntl.h>  
  21. #include "socket.h"  
  22.   
  23. #define MAXFDS 256  
  24.   
  25. int main(int argc,char**argv)  
  26. {  
  27.     int socketFd;  
  28.     int nfds;  
  29.     int epfd;  
  30.     int NewsocketFd;  
  31.     int Count;  
  32.     int rtn;  
  33.     unsigned char buf[1024];  
  34.     struct epoll_event ev, events[MAXFDS];  
  35.       
  36.     if(2 > argc)  
  37.     {  
  38.         Log("Input error\n");  
  39.         Log("Usage: %s <port>\n",argv[0]);  
  40.         Log("Eample: %s 1234\n",argv[0]);  
  41.         return -1;  
  42.     }  
  43.       
  44.     //1、服务器初始化  
  45.     socketFd  = socketServiceInit(atoi(argv[1]));  
  46.     if(0 > socketFd)  
  47.     {  
  48.         Log("Error socketServiceInit\n");  
  49.         return -1;  
  50.     }  
  51.       
  52.       
  53.     do{  
  54.         //~向内核申请MAXFDS+1大小的存储fd的空间  
  55.         epfd = epoll_create(MAXFDS+1);  
  56.         if(0 > epfd)  
  57.         {  
  58.             Log("Error epoll_create\n");   
  59.             break;  
  60.         }  
  61.         //~设置需要监听的fd和触发事件类型  
  62.         ev.data.fd = socketFd;  
  63.         /* 
  64.         EPOLLIN :表示对应的文件描述符可以读;  
  65.         EPOLLOUT:表示对应的文件描述符可以写;  
  66.         EPOLLPRI:表示对应的文件描述符有紧急的数据可读  
  67.         EPOLLERR:表示对应的文件描述符发生错误;  
  68.         EPOLLHUP:表示对应的文件描述符被挂断;  
  69.         EPOLLET:表示对应的文件描述符有事件发生;  
  70.         */  
  71.         ev.events  =  EPOLLIN | EPOLLET;  
  72.         //~控制某个epoll文件描述符上的事件,可以注册事件,修改事件,删除事件  
  73.         rtn = epoll_ctl(epfd,EPOLL_CTL_ADD,socketFd,&ev);  
  74.         /* 
  75.         参数:  
  76.         epfd:由 epoll_create 生成的epoll专用的文件描述符;  
  77.         op:要进行的操作例如注册事件,可能的取值 
  78.             EPOLL_CTL_ADD 注册、 
  79.             EPOLL_CTL_MOD 修 改、 
  80.             EPOLL_CTL_DEL 删除  
  81.  
  82.         fd:关联的文件描述符;  
  83.         event:指向epoll_event的指针;  
  84.             如果调用成功返回0,不成功返回-1  
  85.         */  
  86.         if(0 > rtn)  
  87.         {  
  88.             Log("Error epoll_ctl\n");   
  89.             break;  
  90.         }  
  91.           
  92.         for(;;)  
  93.         {   //~轮询I/O事件的发生  
  94.             nfds = epoll_wait(epfd,events,MAXFDS,0);  
  95.             /* 
  96.             epfd:由epoll_create 生成的epoll专用的文件描述符;  
  97.             epoll_event:用于回传代处理事件的数组;  
  98.             maxevents:每次能处理的事件数;  
  99.             timeout:等待I/O事件发生的超时值; 
  100.                 -1相当于阻塞, 
  101.                 0相当于非阻塞。 
  102.                 一般用-1即可返回发生事件数。  
  103.             */  
  104.             for(Count = 0;Count<nfds;++Count)  
  105.             {     
  106.                 //创建新的请求连接  
  107.                 if(socketFd == events[Count].data.fd)  
  108.                 {  
  109.                     //2、接收客户端的连接请求  
  110.                     NewsocketFd = createSocketRec();  
  111.                     if(0 > NewsocketFd)  
  112.                     {  
  113.                         continue;  
  114.                     }  
  115.                     //将客户端的FD放入epoll中  
  116.                     ev.data.fd = NewsocketFd;  
  117.                     ev.events = EPOLLIN | EPOLLET;  
  118.                     epoll_ctl(epfd,EPOLL_CTL_ADD,NewsocketFd,&ev);  
  119.                 //接收到数据,读socket       
  120.                 }else if(events[Count].events & EPOLLIN){  
  121.                     //Log("read");  
  122.                     if(socketFd == events[Count].data.fd) continue;  
  123.                     bzero(buf,sizeof(buf));  
  124.                     //3、接收客户端数据  
  125.                     rtn = SocketRecv(events[Count].data.fd,buf,sizeof(buf));  
  126.                     if(0 == rtn)  
  127.                     {  
  128.                         Log("Connect Close \n");  
  129.                         epoll_ctl(epfd, EPOLL_CTL_DEL, events[Count].data.fd, NULL);  
  130.                         deleteSocketRec(events[Count].data.fd);  
  131.                         continue;  
  132.                     }  
  133.                     Log("[Recv]: %s",buf);  
  134.                     //4、发送数据到客户端  
  135.                     socketSeverSendAllclients(buf,sizeof(buf));  
  136.                 //有数据待发送,写socket   
  137.                 }else if(events[Count].events & EPOLLOUT){  
  138.                     //Log("write\n");  
  139.                     strcpy(buf,"data from service");  
  140.                     socketSeverSendAllclients(buf,sizeof(buf));  
  141.                 }     
  142.             }  
  143.         }  
  144.           
  145.     }while(0);  
  146.     //5、关闭所有的连接,断开TCP请求  
  147.     socketSeverClose();  
  148.     return 0;  
  149. }  

Client.c程序

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /*************************************************************************************************************  
  2.  * 文件名:             client.c  
  3.  * 功能:              基于TCP创建socket服务端程序 
  4.  * 作者:              edward  
  5.  * 创建时间:        2014年12月31日9:45  
  6.  * 最后修改时间:  2012年3月12日  
  7.  * 详细:              根据的socket建立TCP连接过程,创建客户端程序, 
  8.                     并在与服务器建立连接后,想服务发送数据 
  9. *************************************************************************************************************/    
  10. #include <stdio.h>  
  11. #include <stdlib.h>  
  12. #include <errno.h>  
  13. #include <string.h>  
  14. #include <sys/epoll.h>  
  15. #include <sys/types.h>   
  16. #include <sys/socket.h>  
  17. #include <netinet/in.h>  
  18. #include <poll.h>  
  19. #include <fcntl.h>  
  20. #include "socket.h"  
  21.   
  22. #define SIZE    1024  
  23. int main(int argc,char**argv)  
  24. {  
  25.     int rtn;  
  26.     int socketFd;  
  27.     unsigned char buf[SIZE];  
  28.     unsigned char flag = 1;  
  29.     if(3 > argc)  
  30.     {  
  31.         Log("Input error\n");  
  32.         Log("Usage: %s <IP addr><port>\n",argv[0]);  
  33.         Log("Eample: %s 192.168.0.119 1234\n",argv[0]);  
  34.         return -1;  
  35.     }  
  36.     //1、初始化Socket  
  37.     socketFd  = SocketClientInit(argv[1],argv[2]);  
  38.     if(0 > socketFd)  
  39.     {  
  40.         Log("Error on SocketClientInit function\n ");  
  41.         return -1;  
  42.     }  
  43.     //2、往服务器发送数据,并接收服务器数据  
  44.     while(flag > 0)  
  45.     {  
  46.         bzero(buf,sizeof(buf));  
  47.         printf("Input: ");  
  48.         fgets(buf,SIZE,stdin);  
  49.         rtn = strncmp(buf,"exit",4);  
  50.         if(0 == rtn)  
  51.         {  
  52.             flag = 0;  
  53.         }  
  54.         socketSend(socketFd,buf,sizeof(buf));  
  55.         bzero(buf,sizeof(buf));  
  56.         SocketRecv(socketFd,buf,sizeof(buf));  
  57.         Log("Recv: %s",buf);  
  58.     }  
  59.     //3、关闭的连接  
  60.     socketClientClose(socketFd);  
  61.     return 0;  
  62. }  

socket.c程序

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /*************************************************************************************************************  
  2.  * 文件名:       socket.c  
  3.  * 功能:      socket初始化等操作函数  
  4.  * 作者:      edward  
  5.  * 创建时间:    2014年12月31日9:45  
  6.  * 最后修改时间:2014年12月31日9:45  
  7.  * 详细:          socket操作函数 
  8. *************************************************************************************************************/    
  9. #include <stdio.h>  
  10. #include <stdlib.h>  
  11. #include <string.h>  
  12. #include <unistd.h>  
  13. #include <sys/types.h>   
  14. #include <sys/socket.h>  
  15. #include <netinet/in.h>  
  16. #include <arpa/inet.h>  
  17. #include <fcntl.h>  
  18. #include <sys/signal.h>  
  19. #include <sys/ioctl.h>  
  20. #include <poll.h>  
  21. #include <errno.h>  
  22. #include <assert.h>  
  23. #include "socket.h"  
  24. #define MAX_CLIENTS 50  
  25. socketRecord_t *socketRecordHead = NULL;  
  26.   
  27. /*********************Socket Server 操作函数部分****************/  
  28.   
  29.   
  30. /************************************************************************************************************************* 
  31. *函数        : int socketServiceInit(unsigned int port) 
  32. *功能        : 服务端socket初始化 
  33. *参数        :  port:端口号 
  34. *返回        :  socketFd 
  35. *依赖        : 无 
  36. *作者        : edward 
  37. *时间        : 20141231 
  38. *最后修改时间: 20141231 
  39. *说明        : 在使用epoll的时候需要设置socket为非阻塞模式 
  40. *************************************************************************************************************************/  
  41. int socketServiceInit(unsigned int port)  
  42. {  
  43.     struct sockaddr_in serv_addr;  
  44.     int ret;  
  45.       
  46.     if(NULL != socketRecordHead)  
  47.     {  
  48.         return -1;  
  49.     }  
  50.     //1、分配内存空间用于存储socket的一些数据  
  51.     socketRecord_t *lsSocket = malloc(sizeof(socketRecord_t));    
  52.       
  53.     do{  
  54.         if(NULL == lsSocket)  
  55.             break;  
  56.         //2、创建一个socket连接类型的IPV4 ,流式套接字。  
  57.         lsSocket->socketFd = socket(AF_INET,SOCK_STREAM,0);  
  58.         if(-1 == lsSocket->socketFd)  
  59.         {  
  60.             Log("Error opening Socket: \n");  
  61.             break;  
  62.         }  
  63.         //3、设置的为非阻塞模式  
  64.         fcntl(lsSocket->socketFd,F_SETFL,O_NONBLOCK);  
  65.         bzero(&serv_addr,sizeof(struct sockaddr_in));  
  66.         //4、填充服务器端的sockaddr结构  
  67.         serv_addr.sin_family = AF_INET; //IPV4   
  68.         //(将本机器上的long数据转化为网络上的long数据)服务器程序能运行在任何ip的主机上 //INADDR_ANY 表示主机可以是任意IP地址, 即服务器程序可以绑定到所有的IP上  
  69.         serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);  
  70.         //server_addr.sin_addr.s_addr=inet_addr("192.1 68.1 .1 "); //用 于绑定到一个固定IP,inet_addr用 于把数字加格式的ip转化为整形ip  
  71.         serv_addr.sin_port = htons(port);//设置端口号(将本机器上的short数据转化为网络上的short数据)  
  72.         //5、捆绑socketfd描述符到IP地址  
  73.         ret = bind(lsSocket->socketFd,(struct sockaddr*)&serv_addr,sizeof(serv_addr));  
  74.         if(-1 == ret)  
  75.         {  
  76.             Log("Error on binding: \n");  
  77.             break;  
  78.         }  
  79.         //6、设置允许连接的最大客户端的数目  
  80.         ret = listen(lsSocket->socketFd,10);  
  81.         if(-1 == ret)  
  82.         {  
  83.             Log("Error on Listen: \n");  
  84.             break;  
  85.         }  
  86.         lsSocket->next = NULL;  
  87.         socketRecordHead = lsSocket;  
  88.         Log("Service IP %s:%d\n",inet_ntoa(serv_addr.sin_addr),port);  
  89.         return lsSocket->socketFd;  
  90.     }while(0);  
  91.       
  92.     free(lsSocket);  
  93.     return -1;  
  94. }  
  95.   
  96. /************************************************************************************************************************* 
  97. *函数        : int createSocketRec(void) 
  98. *功能        : 服务端socket初始化 
  99. *参数        : 无 
  100. *返回        : socketfd 
  101.                 -1 失败 
  102. *依赖        : 无 
  103. *作者        : edward 
  104. *时间        : 20141231 
  105. *最后修改时间: 20141231 
  106. *说明        : 在使用epoll的时候需要设置socket为非阻塞模式 
  107. *************************************************************************************************************************/  
  108. int createSocketRec(void)  
  109. {  
  110.     socketRecord_t *srchRec;  
  111.     int ret ,tr = 1;  
  112.     if(NULL == socketRecordHead)  
  113.     {  
  114.         return -1;  
  115.     }  
  116.       
  117.     socketRecord_t *newSocket = malloc(sizeof(socketRecord_t));  
  118.     do{  
  119.         if(NULL == newSocket)break;  
  120.         newSocket->clilen = sizeof(newSocket->cli_addr);  
  121.         //接收客户端连接请求  
  122.         newSocket->socketFd = accept(socketRecordHead->socketFd,(struct sockaddr *) &(newSocket->cli_addr), &(newSocket->clilen));  
  123.   
  124.         if(0 > newSocket->socketFd)  
  125.         {  
  126.             Log("Error on accept: \n");  
  127.             break;  
  128.         }  
  129.         fcntl(newSocket->socketFd, F_SETFL, O_NONBLOCK);  
  130.         newSocket->next = NULL;  
  131.         srchRec = socketRecordHead;  
  132.         while (srchRec->next)  
  133.             srchRec = srchRec->next;  
  134.         srchRec->next = newSocket;  
  135.           
  136.         Log("content from %s\n",inet_ntoa(newSocket->cli_addr.sin_addr));  
  137.         return (newSocket->socketFd);  
  138.     }while(0);  
  139.     Log("Create error\n");  
  140.     free(newSocket);  
  141.     return -1;  
  142. }  
  143. /************************************************************************************************************************* 
  144. *函数        : void deleteSocketRec(int rmSocketFd) 
  145. *功能        : 服务端关闭连接请求 
  146. *参数        : rmSocketFd:  
  147. *返回        : 无 
  148. *依赖        : 无 
  149. *作者        : edward 
  150. *时间        : 20141231 
  151. *最后修改时间: 20141231 
  152. *说明        : 在关闭的同时,需要将该socketFD从单链表中删除 
  153. *************************************************************************************************************************/  
  154. void deleteSocketRec(int rmSocketFd)  
  155. {  
  156.     socketRecord_t *srchRec, *prevRec = NULL;  
  157.   
  158.     // Head of the timer list  
  159.     srchRec = socketRecordHead;  
  160.   
  161.     // Stop when rec found or at the end  
  162.     while ((srchRec->socketFd != rmSocketFd) && (srchRec->next))  
  163.     {  
  164.         prevRec = srchRec;  
  165.         // over to next  
  166.         srchRec = srchRec->next;  
  167.     }  
  168.   
  169.     if (srchRec->socketFd != rmSocketFd)  
  170.     {  
  171.         Log("deleteSocketRec: record not found\n");  
  172.         return;  
  173.     }  
  174.   
  175.     // Does the record exist  
  176.     if (srchRec)  
  177.     {  
  178.         // delete the timer from the list  
  179.         if (prevRec == NULL)  
  180.         {  
  181.             //trying to remove first rec, which is always the listining socket  
  182.             Log(  
  183.                     "deleteSocketRec: removing first rec, which is always the listining socket\n");  
  184.             return;  
  185.         }  
  186.   
  187.         //remove record from list  
  188.         prevRec->next = srchRec->next;  
  189.   
  190.         close(srchRec->socketFd);  
  191.         free(srchRec);  
  192.     }  
  193. }  
  194. /************************************************************************************************************************* 
  195. *函数        : int socketSeverGetNumClients(void) 
  196. *功能        : 服务端获取已经连接的客户端数目 
  197. *参数        : 无 
  198. *返回        : -1:失败 
  199.                 >0 :客户端数目 
  200. *依赖        : 无 
  201. *作者        : edward 
  202. *时间        : 20141231 
  203. *最后修改时间: 20141231 
  204. *说明        : 所有的已经连接上的客户端信息都保存在链表中 
  205. *************************************************************************************************************************/  
  206. int socketSeverGetNumClients(void)  
  207. {  
  208.     int recordCnt = 0;  
  209.     socketRecord_t *srchRec;  
  210.   
  211.     //Log("socketSeverGetNumClients++\n", recordCnt);  
  212.   
  213.     // Head of the timer list  
  214.     srchRec = socketRecordHead;  
  215.   
  216.     if (srchRec == NULL)  
  217.     {  
  218.         //Log("socketSeverGetNumClients: socketRecordHead NULL\n");  
  219.         return -1;  
  220.     }  
  221.   
  222.     // Stop when rec found or at the end  
  223.     while (srchRec)  
  224.     {  
  225.         //Log("socketSeverGetNumClients: recordCnt=%d\n", recordCnt);  
  226.         srchRec = srchRec->next;  
  227.         recordCnt++;  
  228.     }  
  229.   
  230.     //Log("socketSeverGetNumClients %d\n", recordCnt);  
  231.     return (recordCnt);  
  232. }  
  233. /************************************************************************************************************************* 
  234. *函数        : void socketSeverGetClientFds(int *fds, int maxFds) 
  235. *功能        : 服务端关闭连接请求 
  236. *参数        : fds: 存储socketFd的数组 
  237.                maxFds:fds数组大小 
  238. *返回        : 无 
  239. *依赖        : 无 
  240. *作者        : edward 
  241. *时间        : 20141231 
  242. *最后修改时间: 20141231 
  243. *说明        : 遍历链表得到所有socketfd 
  244. *************************************************************************************************************************/  
  245. void socketSeverGetClientFds(int *fds, int maxFds)  
  246. {  
  247.     int recordCnt = 0;  
  248.     socketRecord_t *srchRec;  
  249.   
  250.     assert(fds!=NULL);  
  251.     // Head of the timer list  
  252.     srchRec = socketRecordHead;  
  253.   
  254.     // Stop when at the end or max is reached  
  255.     while ((srchRec) && (recordCnt < maxFds))  
  256.     {  
  257.         //printf("getClientFds: adding fd%d, to idx:%d \n", srchRec->socketFd, recordCnt);  
  258.         fds[recordCnt++] = srchRec->socketFd;  
  259.   
  260.         srchRec = srchRec->next;  
  261.     }  
  262.   
  263.     return;  
  264. }  
  265. /************************************************************************************************************************* 
  266. *函数        : void socketSeverClose(void) 
  267. *功能        : 服务端关闭连接请求 
  268. *参数        : 无  
  269. *返回        : 无 
  270. *依赖        : 无 
  271. *作者        : edward 
  272. *时间        : 20141231 
  273. *最后修改时间: 20141231 
  274. *说明        : 在关闭的同时,需要将该socketFD从单链表中删除 
  275. *************************************************************************************************************************/  
  276. void socketSeverClose(void)  
  277. {  
  278.     int fds[MAX_CLIENTS], idx = 0;  
  279.   
  280.     socketSeverGetClientFds(fds, MAX_CLIENTS);  
  281.   
  282.     while (socketSeverGetNumClients() > 1)  
  283.     {  
  284.         Log("socketSeverClose: Closing socket fd:%d\n", fds[idx]);  
  285.         deleteSocketRec(fds[idx++]);  
  286.     }  
  287.   
  288.     //Now remove the listening socket  
  289.     if (fds[0])  
  290.     {  
  291.         Log("socketSeverClose: Closing the listening socket\n");  
  292.         close(fds[0]);  
  293.     }  
  294. }  
  295. /************************************************************************************************************************* 
  296. *函数        : int socketSeverSendAllclients(unsigned char* buf, int len) 
  297. *功能        : 服务端向所有的客户端发送数据 
  298. *参数        : buf:数据存储  
  299.                len:数据长度 
  300. *返回        : 0:成功 
  301.               -1:失败 
  302. *依赖        : 无 
  303. *作者        : edward 
  304. *时间        : 20141231 
  305. *最后修改时间: 20141231 
  306. *说明        : 无 
  307. *************************************************************************************************************************/  
  308. int socketSeverSendAllclients(unsigned char* buf, int len)  
  309. {  
  310.     int rtn;  
  311.     socketRecord_t *srchRec;  
  312.   
  313.     assert(buf != NULL);  
  314.     // first client socket  
  315.     srchRec = socketRecordHead->next;  
  316.   
  317.     // Stop when at the end or max is reached  
  318.     while (srchRec)  
  319.     {  
  320.         //printf("SRPC_Send: client %d\n", cnt++);  
  321.         rtn = write(srchRec->socketFd, buf, len);  
  322.         if (rtn < 0)  
  323.         {  
  324.             Log("ERROR writing to socket %d\n", srchRec->socketFd);  
  325.             Log("closing client socket\n");  
  326.             //remove the record and close the socket  
  327.             deleteSocketRec(srchRec->socketFd);  
  328.   
  329.             return rtn;  
  330.         }  
  331.         srchRec = srchRec->next;  
  332.     }  
  333.   
  334.     return 0;  
  335. }  
  336.   
  337. /*********************Socket Client 操作函数部分****************/  
  338.   
  339. /************************************************************************************************************************* 
  340. *函数        : int SocketClientInit(const char *addr,const char* port) 
  341. *功能        : 客户端初始化 
  342. *参数        : addr:IP地址 
  343.                port:端口号 
  344. *返回        : socketfd 
  345.                 -1 失败 
  346. *依赖        : 无 
  347. *作者        : edward 
  348. *时间        : 20141231 
  349. *最后修改时间: 20141231 
  350. *说明        : 无 
  351. *************************************************************************************************************************/  
  352. int SocketClientInit(const char *addr,const char* port)  
  353. {  
  354.     int rtn;  
  355.     int socketFd;  
  356.     struct sockaddr_in server_addr;  
  357.       
  358.     assert(addr!=NULL);  
  359.     assert(port!=NULL);  
  360.       
  361.     socketFd = socket(AF_INET,SOCK_STREAM,0);  
  362.     if(0 > socketFd)  
  363.     {  
  364.         Log("Error on socket\n");  
  365.         return -1;  
  366.     }  
  367.       
  368.     bzero(&server_addr,sizeof(struct sockaddr_in));  
  369.     server_addr.sin_family = AF_INET;  
  370.     server_addr.sin_port = htons(atoi(port));  
  371.     server_addr.sin_addr.s_addr = inet_addr(addr);  
  372.       
  373.     rtn = connect(socketFd,(struct sockaddr*)&server_addr,sizeof(struct sockaddr));  
  374.     if(0 > rtn)  
  375.     {  
  376.         Log("Error on connect\n");  
  377.         return -1;  
  378.     }  
  379.       
  380.     return socketFd;  
  381. }  
  382. /************************************************************************************************************************* 
  383. *函数        : int socketClientClose(int socketFd) 
  384. *功能        : 客户端关闭连接请求 
  385. *参数        : socketFd: 客户端文件描述符 
  386. *返回        : 0:成功 
  387.               -1:失败 
  388. *依赖        : 无 
  389. *作者        : edward 
  390. *时间        : 20141231 
  391. *最后修改时间: 20141231 
  392. *说明        : 无 
  393. *************************************************************************************************************************/  
  394. int socketClientClose(int socketFd)  
  395. {  
  396.     if(socketFd)  
  397.     {  
  398.         close(socketFd);  
  399.         return 0;  
  400.     }  
  401.     return -1;  
  402. }  
  403.   
  404. /*********************公共操作函数部分****************/  
  405. /************************************************************************************************************************* 
  406. *函数        : int socketSend(int fdClient,unsigned char* buf, int len) 
  407. *功能        : 服发送数据函数 
  408. *参数        : fdClient: socket文件描述符 
  409.                buf:数据存储区 
  410.                len:数据长度 
  411. *返回        : 返回写入的字节数 
  412.                 -1 写入失败 
  413. *依赖        : 无 
  414. *作者        : edward 
  415. *时间        : 20141231 
  416. *最后修改时间: 20141231 
  417. *说明        : 无 
  418. *************************************************************************************************************************/  
  419. int socketSend(int fdClient,unsigned char* buf, int len)  
  420. {  
  421.     int rtn = -1;  
  422.   
  423.     //Log("socketSend++: writing to socket fd %d\n", fdClient);  
  424.   
  425.     assert(NULL != buf);  
  426.       
  427.     if (fdClient)  
  428.     {  
  429.         rtn = write(fdClient, buf, len);  
  430.         if (rtn < 0)  
  431.         {  
  432.             Log("ERROR writing to socket %d\n", fdClient);  
  433.             return rtn;  
  434.         }  
  435.     }  
  436.   
  437.     //Log("socketSend--\n");  
  438.     return rtn;  
  439. }  
  440.   
  441. /************************************************************************************************************************* 
  442. *函数        : int SocketRecv(int fdClient,unsigned char *buf,int len) 
  443. *功能        : 接收数据函数 
  444. *参数        : fdClient: socket文件描述符 
  445.                buf:数据存储区 
  446.                len:数据长度 
  447. *返回        : 返回读取的字节数 
  448.                 -1 读取失败 
  449. *依赖        : 无 
  450. *作者        : edward 
  451. *时间        : 20141231 
  452. *最后修改时间: 20141231 
  453. *说明        : 无 
  454. *************************************************************************************************************************/  
  455. int SocketRecv(int fdClient,unsigned char *buf,int len)  
  456. {  
  457.     int rtn;  
  458.       
  459.       
  460.     assert(NULL != buf);  
  461.       
  462.     if(fdClient)  
  463.     {  
  464.         rtn = read(fdClient,buf,len);  
  465.         if (rtn < 0)  
  466.         {  
  467.             Log("ERROR Reading to socket %d\n", fdClient);  
  468.             return rtn;  
  469.         }  
  470.     }  
  471.       
  472.     return rtn;  
  473. }  

socket.h头文件定义

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #ifndef __SOCKET_H__  
  2. #define __SOCKET_H__  
  3.   
  4. #include <sys/types.h>   
  5. #include <sys/socket.h>  
  6. #include <netinet/in.h>  
  7. #define DEBUG  
  8. #ifdef  DEBUG  
  9. #define A_OUT printf("%s:%s:%d:", __FILE__, __FUNCTION__,__LINE__);fflush(stdout);  
  10. #define Log(fmt,args...) A_OUT printf(fmt, ##args)  
  11. #else  
  12. #define Log(fmt,args...) printf(fmt, ##args)  
  13. #endif  
  14.   
  15. typedef struct {  
  16.     void *next;  
  17.     int socketFd;  
  18.     socklen_t clilen;  
  19.     struct sockaddr_in cli_addr;  
  20. } socketRecord_t;  
  21.   
  22. #endif  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值