日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

socket编程 及select poll epoll示例

發布時間:2025/3/21 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 socket编程 及select poll epoll示例 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
[cpp] view plain copy
  • ??
  • 1、關于字節排序? ? 網際協議采用大端字節序,來傳輸多字節整數。? ? 系統提供了轉換的宏定義,如果主機與網際協議相同,則宏定義為空。

    2、客戶端? ? socket -> connect(阻塞,三次握手)-> rcv

    3、服務器端? ? socket -> bind -> listen -> accept(阻塞,三次握手)-> send4、函數介紹? ??

    ? ? ?a..socket? ? ? ??

    ? ? ? ? ? 1)函數原型 int socket(int family, int type, int protocol)? ? ? ??

    ? ? ? ? ? 2)參數: ? ?? ? ? ? ? ? family: 協議族AF_INET,IPv4協議 ...? ? ? ? ? ? type : type 套接字類型SOCK_STREAM 字節流套接字? ? ? ? ? ? protocol: IPPROCO_TCP IPPROCO_UDP ? ? ? ? ??? ? ? ? ??IPPROCO_SCTP? ? ? ?

    ?? ? ? ? ?3)返回值? ? ? ? ? ? 成功:返回套接字符? ? ? ? ? ? 錯誤:返回INVALID_SOCKET(-1)? ? ? ??

    ? ? ? ? ?4)示例

    [cpp] view plain copy
  • #include?<netinet/in.h>??
  • #include?<sys/types.h>??
  • #include?<sys/socket.h>??
  • int?main()??
  • {??
  • ????int?socketfd;??
  • ????struct?sockaddr_in?servaddr;??
  • ??
  • ????if((socketfd?=?socket(AF_INET,?SOCK_STREAM,?0))?==?-1)??
  • ????{??
  • ????????return?-1;??
  • ????}??
  • }??


  • ? ? ? ??
    ? ? b..connect
    ? ? ? ? 1)函數原型 int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen)
    ? ? ? ? 2)參數: ? ?
    ? ? ? ? ? ? sockfd: socket 函數返回的套接字描述符
    ? ? ? ? ? ? servaddr : 服務器的IP和端口
    ? ? ? ? ? ? addrlen: 長度(sizeof(servaddr))
    ? ? ? ? 3)返回值
    ? ? ? ? ? ? 成功:0
    ? ? ? ? ? ? 錯誤:返回INVALID_SOCKET(-1)
    ? ? ? ? 4)示例
    [cpp] view plain copy
  • #include?<stdio.h>??
  • #include?<string.h>??
  • #include?<netinet/in.h>??
  • #include?<sys/types.h>??
  • #include?<sys/socket.h>??
  • ??
  • int?main()??
  • {??
  • ????int?socketfd;??
  • ????struct?sockaddr_in?servaddr;??
  • ??
  • ????if((socketfd?=?socket(AF_INET,?SOCK_STREAM,?0))?==?-1)??
  • ????{??
  • ????????printf("socket?error\n");??
  • ????????return?-1;??
  • ????}??
  • ??
  • ????bzero(&servaddr,?sizeof(servaddr));??
  • ??
  • ????servaddr.sin_addr.s_addr?=?inet_addr("192.168.0.218");??
  • ????servaddr.sin_family?=?AF_INET;??
  • ????servaddr.sin_port?=?htons(55000);??
  • ??
  • ????if(connect(socketfd,?(struct?sockaddr*)?&servaddr,?sizeof(servaddr))?<?0)??
  • ????{??
  • ????????printf("connect?error\n");??
  • ????}??
  • ??
  • ????return?0;??
  • }??

  • ? ? c..bind
    ? ? ? ? 1)函數原型 int bind(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen)
    ? ? ? ? 2)參數: ? ?
    ? ? ? ? ? ? sockfd: socket 函數返回的套接字描述符
    ? ? ? ? ? ? servaddr : 服務器的IP和端口
    ? ? ? ? ? ? addrlen: 長度(sizeof(servaddr))
    ? ? ? ? 3)返回值
    ? ? ? ? ? ? 成功:0
    ? ? ? ? ? ? 錯誤:返回INVALID_SOCKET(-1)
    ? ? ? ? ? ??
    ? ? d..listen
    ? ? ? ? 1)函數原型 int listen(int sockfd, int backlog)
    ? ? ? ? 2)參數: ? ?
    ? ? ? ? ? ? sockfd: socket 函數返回的套接字描述符
    ? ? ? ? ? ? backlog : 內核中套接字排隊的最大個數
    ? ? ? ? 3)返回值
    ? ? ? ? ? ? 成功:0
    ? ? ? ? ? ? 錯誤:返回INVALID_SOCKET
    ? ? ? ? ? ? ? ??
    ? ? e..accept
    ? ? ? ? 1)函數原型 int accept(int sockfd, const struct sockaddr *servaddr, socklen_t *addrlen)
    ? ? ? ? 2)參數: ? ?
    ? ? ? ? ? ? sockfd: socket 函數返回的套接字描述符


    ? ? ? ? 3)返回值
    ? ? ? ? ? ? servaddr : 客戶進程的IP和端口(可設為null)
    ? ? ? ? ? ? addrlen: 長度(sizeof(servaddr))(可設為null)
    ? ? ? ? ? ? 成功:從監聽套接字返回已連接套接字
    ? ? ? ? ? ? 錯誤:
    ? ? ? ? ? ? 如果對客戶信息不感興趣,后兩個參數可以置空。

    ? ? ? ? 4)示例

    [cpp] view plain copy
  • #include?<stdio.h>??
  • #include?<string.h>??
  • #include?<netinet/in.h>??
  • #include?<sys/types.h>??
  • #include?<sys/socket.h>??
  • ??
  • int?main()??
  • {??
  • ????int?count?=?0;??
  • ????int?listenfd,?socketfd;??
  • ????int?nread;??
  • ????struct?sockaddr_in?servaddr;??
  • ????struct?timeval?timeoutval;??
  • ????char?readbuf[256];??
  • ??
  • ????printf("accept?started\n");??
  • ??
  • ????//socket??????
  • ????if((listenfd?=?socket(AF_INET,?SOCK_STREAM,?0))?==?-1)??
  • ????{??
  • ????????printf("socket?error\n");??
  • ????????return?-1;??
  • ????}??
  • ??
  • ????bzero(&servaddr,?sizeof(servaddr));??
  • ????servaddr.sin_addr.s_addr?=?htonl(INADDR_ANY);??
  • ????servaddr.sin_family?=?AF_INET;??
  • ????servaddr.sin_port?=?htons(59000);??
  • ??
  • ????//bind??
  • ????if(bind(listenfd,?(struct?sockaddr*)&servaddr,?sizeof(servaddr))?<?0)??
  • ????{??
  • ????????printf("bind?error\n");??
  • ????????//return?-1;??
  • ????}??
  • ??
  • ????//listen??
  • ????listen(listenfd,?5);??
  • ??
  • ????//accept??
  • ????socketfd?=?accept(listenfd,?NULL,?NULL);??
  • ??
  • ??
  • ??
  • ????while(1)??
  • ????{??
  • ????????printf("start?receive?%d...\n",?count++);??
  • ????????memset(readbuf,?sizeof(readbuf),?0);??
  • ??
  • ????????nread?=?recv(socketfd,?readbuf,?10,?0);??
  • ????????if(nread>0)??
  • ????????{??
  • ????????????readbuf[10]?=?'\0';??
  • ????????????printf("receiveed?%s,?nread?=?%d\n\n",?readbuf,?nread);??
  • ????????}??
  • ????}??
  • ??
  • ????return?0;??
  • }??

  • ? ? /**************************************************************
    ? ? 從 I/O 事件分派機制來看,使用 select()是不合適的,因為它所支持的并發連接數有限(通
    ? ? 常在 1024 個以內)。如果考慮性能,poll()也是不合適的,盡管它可以支持的較高的 TCP 并發
    ? ? 數,但是由于其采用“輪詢”機制,當并發數較高時,其運行效率相當低,并可能存在 I/O 事
    ? ? 件分派不均,導致部分 TCP 連接上的 I/O 出現“饑餓”現象。而如果使用 epoll 或 AIO,則沒
    ? ? 有上述問題(早期 Linux 內核的 AIO 技術實現是通過在內核中為每個 I/O 請求創建一個線程來
    ? ? 實現的,這種實現機制在高并發 TCP 連接的情形下使用其實也有嚴重的性能問題。但在最新的
    ? ? Linux 內核中,AIO 的實現已經得到改進)。
    ? ? 支持一個進程打開大數目的 socket 描述符(FD)select 最不能忍受的是一個進程所打開的
    ? ? FD 是有一定限制的,由 FD_SETSIZE 設置,默認值是 2048。對于那些需要支持的上萬連接數目
    ? ? 的 IM 服務器來說顯然太少了。
    ? ? 這時候你一是可以選擇修改這個宏然后重新編譯內核,不過資料
    ? ? 也同時指出這樣會帶來網絡效率的下降,二是可以選擇多進程的解決方案(傳統的 Apache 方
    ? ? 案),不過雖然 linux 上面創建進程的代價比較小,但仍舊是不可忽視的,加上進程間數據同步
    ? ? 遠比不上線程間同步的高效,所以也不是一種完美的方案。不過 epoll 則沒有這個限制,它所
    ? ? 支持的 FD 上限是最大可以打開文件的數目,這個數字一般遠大于 2048,舉個例子,在 1GB 內存
    ? ? 的機器上大約是 10 萬左右,具體數目可以 cat /proc/sys/fs/file-max 察看,一般來說這個數
    ? ? 目和系統內存關系很大。
    ? ? ******************************************************************/ ? ? ? ?
    5. select函數
    ? ? 1)函數原型 int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);
    ? ? 2)參數: ? ?
    ? ? ? ? sockfd: socket 函數返回的套接字描述符
    ? ? ? ? readfds : 讀描述符集合
    ? ? ? ? writefds: 寫描述符集合
    ? ? ? ? errorfds: 錯誤描述符集合
    ? ? ? ? timeout: ?超時
    ? ? 3)返回值
    ? ? ? ? 成功:返回值 0:無 >0:描述符就緒的總位數
    ? ? ? ? 錯誤:返回INVALID_SOCKET(-1)
    ? ? 4)包含頭文件: include <sys/select.h> include <sys/time.h>
    ? ? 5)示例
    [cpp] view plain copy
  • /*?實現功能:通過select處理多個socket?
  • ?*?監聽一個端口,監聽到有鏈接時,添加到select的w.?
  • ?*/??
  • #include?"select.h"??
  • #include?<stdio.h>??
  • #include?<stdlib.h>??
  • #include?<sys/socket.h>??
  • #include?<sys/select.h>??
  • #include?<sys/time.h>??
  • #include?<netinet/in.h>??
  • ??
  • typedef?struct?_CLIENT{??
  • ????int?fd;??
  • ????struct?sockaddr_in?addr;?/*?client's?address?information?*/??
  • }?CLIENT;??
  • ??
  • #define?MYPORT?59000??
  • ??
  • //最多處理的connect??
  • #define?BACKLOG?5??
  • ??
  • //最多處理的connect??
  • CLIENT?client[BACKLOG];??
  • ??
  • //當前的連接數??
  • int?currentClient?=?0;???
  • ??
  • //數據接受?buf??
  • #define?REVLEN?10??
  • char?recvBuf[REVLEN];??
  • //顯示當前的connection??
  • void?showClient();??
  • ??
  • int?main()??
  • {??
  • ????int?i,?ret,?sinSize;??
  • ????int?recvLen?=?0;??
  • ????fd_set?readfds,?writefds;??
  • ????int?sockListen,?sockSvr,?sockMax;??
  • ????struct?timeval?timeout;??
  • ????struct?sockaddr_in?server_addr;??
  • ????struct?sockaddr_in?client_addr;??
  • ??
  • ????for(i=0;?i<BACKLOG;?i++)??
  • ????{??
  • ????????client[i].fd?=?-1;??
  • ????}??
  • ??
  • ????//socket??
  • ????if((sockListen=socket(AF_INET,?SOCK_STREAM,?0))?<?0)??
  • ????{??
  • ????????printf("socket?error\n");??
  • ????????return?-1;??
  • ????}??
  • ??
  • ????bzero(&server_addr,?sizeof(server_addr));??
  • ????server_addr.sin_family??=??AF_INET;??
  • ????server_addr.sin_port?=?htons(MYPORT);??
  • ????server_addr.sin_addr.s_addr??=??htonl(INADDR_ANY);???
  • ??
  • ????//bind??
  • ????if(bind(sockListen,?(struct?sockaddr*)&server_addr,?sizeof(server_addr))?<?0)??
  • ????{??
  • ????????printf("bind?error\n");??
  • ????????return?-1;??
  • ????}??
  • ??
  • ????//listen??
  • ????if(listen(sockListen,?5)?<?0)??
  • ????{??
  • ????????printf("listen?error\n");??
  • ????????return?-1;??
  • ????}??
  • ??
  • ????for(i=0;?i<BACKLOG;?i++)??
  • ????{??
  • ????????client[i].fd?=?-1;??
  • ????}??
  • ??
  • ????//select??
  • ????while(1)??
  • ????{??
  • ????????FD_ZERO(&readfds);??
  • ????????FD_SET(sockListen,?&readfds);??
  • ????????sockMax?=?sockListen;??
  • ??????
  • ????????//加入client??
  • ????????for(i=0;?i<BACKLOG;?i++)??
  • ????????{??
  • ????????????if(client[i].fd?>0)??
  • ????????????{??
  • ????????????????FD_SET(client[i].fd,?&readfds);??
  • ????????????????if(sockMax<client[i].fd)???
  • ????????????????????sockMax?=?client[i].fd;??
  • ????????????}??
  • ????????}??
  • ??????????
  • ????????timeout.tv_sec=3;??????????????????
  • ????????timeout.tv_usec=0;??
  • ????????//select??
  • ????????ret?=?select((int)sockMax+1,?&readfds,?NULL,?NULL,?&timeout);??
  • ????????if(ret?<?0)??
  • ????????{??
  • ????????????printf("select?error\n");??
  • ????????????break;??
  • ????????}??
  • ????????else?if(ret?==?0)??
  • ????????{??
  • ????????????printf("timeout?...\n");??
  • ????????????continue;??
  • ????????}??
  • ????????printf("test111\n");??
  • ??????
  • ????????//讀取數據??
  • ????????for(i=0;?i<BACKLOG;?i++)??
  • ????????{??
  • ????????????if(client[i].fd>0?&&?FD_ISSET(client[i].fd,?&readfds))??
  • ????????????{??
  • ????????????????if(recvLen?!=?REVLEN)??
  • ????????????????{??
  • ????????????????????while(1)??
  • ????????????????????{??
  • ????????????????????????//recv數據??
  • ????????????????????????ret?=?recv(client[i].fd,?(char?*)recvBuf+recvLen,?REVLEN-recvLen,?0);??
  • ????????????????????????if(ret?==?0)??
  • ????????????????????????{??
  • ????????????????????????????client[i].fd?=?-1;??
  • ????????????????????????????recvLen?=?0;??
  • ????????????????????????????break;??
  • ????????????????????????}??
  • ????????????????????????else?if(ret?<?0)??
  • ????????????????????????{??
  • ????????????????????????????client[i].fd?=?-1;??
  • ????????????????????????????recvLen?=?0;??
  • ????????????????????????????break;??
  • ????????????????????????}??
  • ????????????????????????//數據接受正常??
  • ????????????????????????recvLen?=?recvLen+ret;??
  • ????????????????????????if(recvLen<REVLEN)??
  • ????????????????????????{??
  • ????????????????????????????continue;??
  • ????????????????????????}??
  • ????????????????????????else??
  • ????????????????????????{??
  • ????????????????????????????//數據接受完畢??
  • ????????????????????????????printf("%s,?buf?=?%s\n",?inet_ntoa(client[i].addr.sin_addr)?,?recvBuf);??
  • ????????????????????????????//close(client[i].fd);??
  • ????????????????????????????//client[i].fd?=?-1;??
  • ????????????????????????????recvLen?=?0;??
  • ????????????????????????????break;??
  • ????????????????????????}??
  • ????????????????????}??
  • ????????????????}??
  • ????????????}??
  • ????????}??
  • ??????
  • ????????//如果可讀??
  • ????????if(FD_ISSET(sockListen,?&readfds))??
  • ????????{??
  • ????????????printf("isset\n");??
  • ????????????sockSvr?=?accept(sockListen,?NULL,?NULL);//(struct?sockaddr*)&client_addr??
  • ??????????
  • ????????????if(sockSvr?==?-1)??
  • ????????????{??
  • ????????????????printf("accpet?error\n");??
  • ????????????}??
  • ????????????else??
  • ????????????{??
  • ????????????????currentClient++;??
  • ????????????}??
  • ??????????
  • ????????????for(i=0;?i<BACKLOG;?i++)??
  • ????????????{??
  • ????????????????if(client[i].fd?<?0)??
  • ????????????????{??
  • ????????????????????client[i].fd?=?sockSvr;??
  • ????????????????????client[i].addr?=?client_addr;??
  • ????????????????????printf("You?got?a?connection?from?%s?\n",inet_ntoa(client[i].addr.sin_addr)?);??
  • ????????????????????break;??
  • ????????????????}??
  • ????????????}??
  • ????????????//close(sockListen);??
  • ????????}??
  • ????}??
  • ??
  • ????printf("test\n");??
  • ????return?0;??
  • }??
  • ??
  • //顯示當前的connection??
  • void?showClient()??
  • {??
  • ????int?i;??
  • ????printf("client?count?=?%d\n",?currentClient);??
  • ??
  • ????for(i=0;?i<BACKLOG;?i++)??
  • ????{??
  • ????????printf("[%d]?=?%d",?i,?client[i].fd);??
  • ????}??
  • ????printf("\n");??
  • }??

  • 6. poll函數
    ? ? 1)函數原型 int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);
    ? ? 2)參數: ? ?
    ? ? ? ? sockfd: socket 函數返回的套接字描述符
    ? ? ? ? readfds : 讀描述符集合
    ? ? ? ? writefds: 寫描述符集合
    ? ? ? ? errorfds: 錯誤描述符集合
    ? ? ? ? timeout: ?超時
    ? ? 3)返回值
    ? ? ? ? 成功:返回值 0:無 >0:描述符就緒的總位數
    ? ? ? ? 錯誤:返回INVALID_SOCKET(-1)
    ? ? 4)包含頭文件: include <sys/select.h> include <sys/time.h>

    ? ? 5) 示例

    [cpp] view plain copy
  • /*?實現功能:通過poll,?處理多個socket?
  • ?*?監聽一個端口,監聽到有鏈接時,添加到poll.?
  • ?*/??
  • #include?"select.h"??
  • #include?<stdio.h>??
  • #include?<stdlib.h>??
  • #include?<string.h>??
  • #include?<sys/socket.h>??
  • #include?<poll.h>??
  • #include?<sys/time.h>??
  • #include?<netinet/in.h>??
  • ??
  • typedef?struct?_CLIENT{??
  • ????int?fd;??
  • ????struct?sockaddr_in?addr;?/*?client's?address?information?*/??
  • }?CLIENT;??
  • ??
  • #define?MYPORT?59000??
  • ??
  • //最多處理的connect??
  • #define?BACKLOG?5??
  • ??
  • //當前的連接數??
  • int?currentClient?=?0;???
  • ??
  • //數據接受?buf??
  • #define?REVLEN?10??
  • char?recvBuf[REVLEN];??
  • ??
  • #define?OPEN_MAX?1024??
  • ??
  • int?main()??
  • {??
  • ????int?i,?ret,?sinSize;??
  • ????int?recvLen?=?0;??
  • ????fd_set?readfds,?writefds;??
  • ????int?sockListen,?sockSvr,?sockMax;??
  • ????int?timeout;??
  • ????struct?sockaddr_in?server_addr;??
  • ????struct?sockaddr_in?client_addr;??
  • ??
  • ????struct?pollfd?clientfd[OPEN_MAX];??
  • ??
  • ??
  • ????//socket??
  • ????if((sockListen=socket(AF_INET,?SOCK_STREAM,?0))?<?0)??
  • ????{??
  • ????????printf("socket?error\n");??
  • ????????return?-1;??
  • ????}??
  • ??
  • ????bzero(&server_addr,?sizeof(server_addr));??
  • ????server_addr.sin_family??=??AF_INET;??
  • ????server_addr.sin_port?=?htons(MYPORT);??
  • ????server_addr.sin_addr.s_addr??=??htonl(INADDR_ANY);???
  • ??
  • ????//bind??
  • ????if(bind(sockListen,?(struct?sockaddr*)&server_addr,?sizeof(server_addr))?<?0)??
  • ????{??
  • ????????printf("bind?error\n");??
  • ????????return?-1;??
  • ????}??
  • ??
  • ????//listen??
  • ????if(listen(sockListen,?5)?<?0)??
  • ????{??
  • ????????printf("listen?error\n");??
  • ????????return?-1;??
  • ????}??
  • ??
  • ??
  • ????//clientfd?初始化??
  • ????clientfd[0].fd?=?sockListen;??
  • ????clientfd[0].events?=?POLLIN;?//POLLRDNORM;??
  • ????sockMax?=?0;??
  • ????for(i=1;?i<OPEN_MAX;?i++)??
  • ????{??
  • ????????clientfd[i].fd?=?-1;??
  • ????}??
  • ??
  • ????//select??
  • ????while(1)??
  • ????{??
  • ????????timeout=3000;??????????????????
  • ????????//select??
  • ????????ret?=?poll(clientfd,?sockMax+1,?timeout);??
  • ??????
  • ????????if(ret?<?0)??
  • ????????{??
  • ????????????printf("select?error\n");??
  • ????????????break;??
  • ????????}??
  • ????????else?if(ret?==?0)??
  • ????????{??
  • ????????????printf("timeout?...\n");??
  • ????????????continue;??
  • ????????}??
  • ??????
  • ????????if?(clientfd[0].revents?&?POLLIN)//POLLRDNORM??
  • ????????{??
  • ????????????sockSvr?=?accept(sockListen,?NULL,?NULL);//(struct?sockaddr*)&client_addr??
  • ??????????
  • ????????????if(sockSvr?==?-1)??
  • ????????????{??
  • ????????????????printf("accpet?error\n");??
  • ????????????}??
  • ????????????else??
  • ????????????{??
  • ????????????????currentClient++;??
  • ????????????}??
  • ??????????
  • ????????????for(i=0;?i<OPEN_MAX;?i++)??
  • ????????????{??
  • ????????????????if(clientfd[i].fd<0)??
  • ????????????????{??
  • ????????????????????clientfd[i].fd?=?sockSvr;??
  • ????????????????????break;??
  • ????????????????}??
  • ????????????}??
  • ????????????if(i==OPEN_MAX)??
  • ????????????{??
  • ????????????????printf("too?many?connects\n");??
  • ????????????????return?-1;??
  • ????????????}??
  • ????????????clientfd[i].events?=?POLLIN;//POLLRDNORM;??
  • ????????????if(i>sockMax)??
  • ????????????????sockMax?=?i;??
  • ????????}??
  • ??????
  • ????????//讀取數據??
  • ????????for(i=1;?i<=sockMax;?i++)??
  • ????????{??
  • ????????????if(clientfd[i].fd?<?0)??
  • ????????????????continue;??
  • ??????????
  • ????????????if?(clientfd[i].revents?&?(POLLIN?|?POLLERR))//POLLRDNORM??
  • ????????????{??
  • ????????????????if(recvLen?!=?REVLEN)??
  • ????????????????{??
  • ????????????????????while(1)??
  • ????????????????????{??
  • ????????????????????????//recv數據??
  • ????????????????????????ret?=?recv(clientfd[i].fd,?(char?*)recvBuf+recvLen,?REVLEN-recvLen,?0);??
  • ????????????????????????if(ret?==?0)??
  • ????????????????????????{??
  • ????????????????????????????clientfd[i].fd?=?-1;??
  • ????????????????????????????recvLen?=?0;??
  • ????????????????????????????break;??
  • ????????????????????????}??
  • ????????????????????????else?if(ret?<?0)??
  • ????????????????????????{??
  • ????????????????????????????clientfd[i].fd?=?-1;??
  • ????????????????????????????recvLen?=?0;??
  • ????????????????????????????break;??
  • ????????????????????????}??
  • ????????????????????????//數據接受正常??
  • ????????????????????????recvLen?=?recvLen+ret;??
  • ????????????????????????if(recvLen<REVLEN)??
  • ????????????????????????{??
  • ????????????????????????????continue;??
  • ????????????????????????}??
  • ????????????????????????else??
  • ????????????????????????{??
  • ????????????????????????????//數據接受完畢??
  • ????????????????????????????printf("buf?=?%s\n",??recvBuf);??
  • ????????????????????????????//close(client[i].fd);??
  • ????????????????????????????//client[i].fd?=?-1;??
  • ????????????????????????????recvLen?=?0;??
  • ????????????????????????????break;??
  • ????????????????????????}??
  • ????????????????????}??
  • ????????????????}??
  • ????????????}??
  • ????????}??
  • ????}??
  • ??
  • ????return?0;??
  • }??

  • 6. epoll函數
    ? ? ? ? 2. 常用模型的缺點
    ? ? ? ? 如果不擺出來其他模型的缺點,怎么能對比出 Epoll 的優點呢。
    ? ? ? ? 2.1 PPC/TPC 模型
    ? ? ? ? 這兩種模型思想類似,就是讓每一個到來的連接一邊自己做事去,別再來煩我 。只是 PPC 是為它開了一個進程,而 TPC 開了一個線程。可是別煩我是有代價的,它要時間和空間啊,連接多了之后,那么多的進程 / 線程切換,這開銷就上來了;因此這類模型能接受的最大連接數都不會高,一般在幾百個左右。
    ? ? ? ? 2.2 select 模型
    ? ? ? ? 1. 最大并發數限制,因為一個進程所打開的 FD (文件描述符)是有限制的,由 FD_SETSIZE 設置,默認值是 1024/2048 ,因此 Select 模型的最大并發數就被相應限制了。自己改改這個 FD_SETSIZE ?想法雖好,可是先看看下面吧 …
    ? ? ? ? 2. 效率問題, select 每次調用都會線性掃描全部的 FD 集合,這樣效率就會呈現線性下降,把 FD_SETSIZE 改大的后果就是,大家都慢慢來,什么?都超時了??!!
    ? ? ? ? 3. 內核 / 用戶空間 內存拷貝問題,如何讓內核把 FD 消息通知給用戶空間呢?在這個問題上 select 采取了內存拷貝方法。
    ? ? ? ? 2.3 poll 模型
    ? ? ? ? 基本上效率和 select 是相同的, select 缺點的 2 和 3 它都沒有改掉。
    ? ? ? ? 3. Epoll 的提升
    ? ? ? ? 把其他模型逐個批判了一下,再來看看 Epoll 的改進之處吧,其實把 select 的缺點反過來那就是 Epoll 的優點了。
    ? ? ? ? 3.1. Epoll 沒有最大并發連接的限制,上限是最大可以打開文件的數目,這個數字一般遠大于 2048, 一般來說這個數目和系統內存關系很大 ,具體數目可以 cat /proc/sys/fs/file-max 察看。
    ? ? ? ? 3.2. 效率提升, Epoll 最大的優點就在于它只管你“活躍”的連接 ,而跟連接總數無關,因此在實際的網絡環境中, Epoll 的效率就會遠遠高于 select 和 poll 。
    ? ? ? ? 3.3. 內存拷貝, Epoll 在這點上使用了“共享內存 ”,這個內存拷貝也省略了。
    ? ? ? ? ?
    ? ? ? ? 4. Epoll 為什么高效
    ? ? ? ? Epoll 的高效和其數據結構的設計是密不可分的,這個下面就會提到。
    ? ? ? ? 首先回憶一下 select 模型,當有 I/O 事件到來時, select 通知應用程序有事件到了快去處理,而應用程序必須輪詢所有的 FD 集合,測試每個 FD 是否有事件發生,并處理事件;代碼像下面這樣:


    ? ? ? ? int res = select(maxfd+1, &readfds, NULL, NULL, 120);
    ? ? ? ? if (res > 0)
    ? ? ? ? {
    ? ? ? ? ? ? for (int i = 0; i < MAX_CONNECTION; i++)
    ? ? ? ? ? ? {
    ? ? ? ? ? ? ? ? if (FD_ISSET(allConnection[i], &readfds))
    ? ? ? ? ? ? ? ? {
    ? ? ? ? ? ? ? ? ? ? handleEvent(allConnection[i]);
    ? ? ? ? ? ? ? ? }
    ? ? ? ? ? ? }
    ? ? ? ? }
    ? ? ? ? // if(res == 0) handle timeout, res < 0 handle error
    ? ? ? ? ?
    ? ? ? ? Epoll 不僅會告訴應用程序有I/0 事件到來,還會告訴應用程序相關的信息,這些信息是應用程序填充的,因此根據這些信息應用程序就能直接定位到事件,而不必遍歷整個FD 集合。
    ? ? ? ? int res = epoll_wait(epfd, events, 20, 120);
    ? ? ? ? for (int i = 0; i < res;i++)
    ? ? ? ? {
    ? ? ? ? ? ? handleEvent(events[n]);
    ? ? ? ? }
    ? ? ? ? 5. Epoll 關鍵數據結構
    ? ? ? ? 前面提到 Epoll 速度快和其數據結構密不可分,其關鍵數據結構就是:
    ? ? ? ? struct epoll_event {
    ? ? ? ? ? ? __uint32_t events; ? ? ?// Epoll events
    ? ? ? ? ? ? epoll_data_t data; ? ? ?// User data variable
    ? ? ? ? };
    ? ? ? ? typedef union epoll_data {
    ? ? ? ? ? ? void *ptr;
    ? ? ? ? ? ? int fd;
    ? ? ? ? ? ? __uint32_t u32;
    ? ? ? ? ? ? __uint64_t u64;
    ? ? ? ? } epoll_data_t;
    ? ? ? ??
    ? ? ? ? 可見 epoll_data 是一個 union 結構體 , 借助于它應用程序可以保存很多類型的信息 :fd 、指針等等。有了它,應用程序就可以直接定位目標了。
    ? ? ? ? 6. 使用 Epoll
    ? ? ? ? 既然 Epoll 相比 select 這么好,那么用起來如何呢?會不會很繁瑣啊 … 先看看下面的三個函數吧,就知道 Epoll 的易用了。
    ? ? ? ? ?
    ? ? ? ? int epoll_create(int size);
    ? ? ? ? 生成一個 Epoll 專用的文件描述符,其實是申請一個內核空間,用來存放你想關注的 socket fd 上是否發生以及發生了什么事件。 size 就是你在這個 Epoll fd 上能關注的最大 socket fd 數,大小自定,只要內存足夠。
    ? ? ? ??
    ? ? ? ? int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event );
    ? ? ? ? 控制某個 Epoll 文件描述符上的事件:注冊、修改、刪除。其中參數 epfd 是 epoll_create() 創建 Epoll 專用的文件描述符。相對于 select 模型中的 FD_SET 和 FD_CLR 宏。
    ? ? ? ? op:EPOLL_CTL_ADD
    ? ? ? ? ? ? ? ? ?Register the target file descriptor fd on the epoll instance?
    ? ? ? ? ? ? ? EPOLL_CTL_MOD
    ? ? ? ? ? ? ? ? ? Change the event event associated with the target file descriptor fd.
    ? ? ? ? ? ? ? EPOLL_CTL_DEL
    ? ? ? ? ? ? ? ? ? ?Remove ?(deregister) ?the ?target ?file descriptor fd from the epoll instance


    ? ? ? ??
    ? ? ? ? int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout);
    ? ? ? ? 等待 I/O 事件的發生;參數說明:
    ? ? ? ? epfd: 由 epoll_create() 生成的 Epoll 專用的文件描述符;
    ? ? ? ? epoll_event: 用于回傳代處理事件的數組;
    ? ? ? ? maxevents: 每次能處理的事件數;
    ? ? ? ? timeout: 等待 I/O 事件發生的超時值,單位 ms
    ? ? ? ? 返回發生事件數。
    ? ? ? ? 相對于 select 模型中的 select 函數。
    ? ? ? ??
    [cpp] view plain copy
  • /*?實現功能:通過epoll,?處理多個socket?
  • ?*?監聽一個端口,監聽到有鏈接時,添加到epoll_event?
  • ?*/??
  • #include?"select.h"??
  • #include?<stdio.h>??
  • #include?<stdlib.h>??
  • #include?<string.h>??
  • #include?<sys/socket.h>??
  • #include?<poll.h>??
  • #include?<sys/epoll.h>??
  • #include?<sys/time.h>??
  • #include?<netinet/in.h>??
  • ??
  • typedef?struct?_CLIENT{??
  • ????int?fd;??
  • ????struct?sockaddr_in?addr;?/*?client's?address?information?*/??
  • }?CLIENT;??
  • ??
  • #define?MYPORT?59000??
  • ??
  • //最多處理的connect??
  • #define?MAX_EVENTS?500??
  • ??
  • //當前的連接數??
  • int?currentClient?=?0;???
  • ??
  • //數據接受?buf??
  • #define?REVLEN?10??
  • char?recvBuf[REVLEN];??
  • ??
  • //EPOLL相關???
  • //epoll描述符??
  • int?epollfd;??
  • //事件數組??
  • struct?epoll_event?eventList[MAX_EVENTS];??
  • ??
  • void?AcceptConn(int?srvfd);??
  • void?RecvData(int?fd);??
  • ??
  • int?main()??
  • {??
  • ????int?i,?ret,?sinSize;??
  • ????int?recvLen?=?0;??
  • ????fd_set?readfds,?writefds;??
  • ????int?sockListen,?sockSvr,?sockMax;??
  • ????int?timeout;??
  • ????struct?sockaddr_in?server_addr;??
  • ????struct?sockaddr_in?client_addr;??
  • ??????
  • ????//socket??
  • ????if((sockListen=socket(AF_INET,?SOCK_STREAM,?0))?<?0)??
  • ????{??
  • ????????printf("socket?error\n");??
  • ????????return?-1;??
  • ????}??
  • ??????
  • ????bzero(&server_addr,?sizeof(server_addr));??
  • ????server_addr.sin_family??=??AF_INET;??
  • ????server_addr.sin_port?=?htons(MYPORT);??
  • ????server_addr.sin_addr.s_addr??=??htonl(INADDR_ANY);???
  • ??????
  • ????//bind??
  • ????if(bind(sockListen,?(struct?sockaddr*)&server_addr,?sizeof(server_addr))?<?0)??
  • ????{??
  • ????????printf("bind?error\n");??
  • ????????return?-1;??
  • ????}??
  • ??????
  • ????//listen??
  • ????if(listen(sockListen,?5)?<?0)??
  • ????{??
  • ????????printf("listen?error\n");??
  • ????????return?-1;??
  • ????}??
  • ??????
  • ????//1.?epoll?初始化??
  • ????epollfd?=?epoll_create(MAX_EVENTS);??
  • ????struct?epoll_event?event;??
  • ????event.events?=?EPOLLIN|EPOLLET;??
  • ????event.data.fd?=?sockListen;??
  • ??????
  • ????//2.?epoll_ctrl??
  • ????if(epoll_ctl(epollfd,?EPOLL_CTL_ADD,?sockListen,?&event)?<?0)??
  • ????{??
  • ????????printf("epoll?add?fail?:?fd?=?%d\n",?sockListen);??
  • ????????return?-1;??
  • ????}??
  • ??????
  • ????//epoll??
  • ????while(1)??
  • ????{??
  • ????????timeout=3000;??????????????????
  • ????????//3.?epoll_wait??
  • ????????int?ret?=?epoll_wait(epollfd,?eventList,?MAX_EVENTS,?timeout);??
  • ??????????
  • ????????if(ret?<?0)??
  • ????????{??
  • ????????????printf("epoll?error\n");??
  • ????????????break;??
  • ????????}??
  • ????????else?if(ret?==?0)??
  • ????????{??
  • ????????????printf("timeout?...\n");??
  • ????????????continue;??
  • ????????}??
  • ??????????
  • ????????//直接獲取了事件數量,給出了活動的流,這里是和poll區別的關鍵??
  • ????????int?n?=?0;??
  • ????????for(n=0;?n<ret;?n++)??
  • ????????{??
  • ????????????//錯誤退出??
  • ????????????if?((eventList[n].events?&?EPOLLERR)?||??
  • ????????????????(eventList[n].events?&?EPOLLHUP)?||??
  • ????????????????!(eventList[n].events?&?EPOLLIN))??
  • ????????????{??
  • ??????????????printf?(?"epoll?error\n");??
  • ??????????????close?(eventList[n].data.fd);??
  • ??????????????return?-1;??
  • ????????????}??
  • ??????????????
  • ????????????if?(eventList[n].data.fd?==?sockListen)??
  • ????????????{??
  • ????????????????AcceptConn(sockListen);??
  • ??????????
  • ????????????}else{??
  • ????????????????RecvData(eventList[n].data.fd);??
  • ????????????????//不刪除??
  • ?????????????//???epoll_ctl(epollfd,?EPOLL_CTL_DEL,?pEvent->data.fd,?pEvent);??
  • ????????????}??
  • ????????}??
  • ????}??
  • ??????
  • ????close(epollfd);??
  • ????close(sockListen);??
  • ??????
  • ????printf("test\n");??
  • ????return?0;??
  • }??
  • ??
  • /**************************************************?
  • 函數名:AcceptConn?
  • 功能:接受客戶端的鏈接?
  • 參數:srvfd:監聽SOCKET?
  • ***************************************************/??
  • void?AcceptConn(int?srvfd)??
  • {??
  • ????struct?sockaddr_in?sin;??
  • ????socklen_t?len?=?sizeof(struct?sockaddr_in);??
  • ????bzero(&sin,?len);??
  • ??
  • ????int?confd?=?accept(srvfd,?(struct?sockaddr*)&sin,?&len);??
  • ??
  • ????if?(confd?<?0)??
  • ????{??
  • ???????printf("bad?accept\n");??
  • ???????return;??
  • ????}else??
  • ????{??
  • ????????printf("Accept?Connection:?%d",?confd);??
  • ????}??
  • ??
  • ????//setnonblocking(confd);??
  • ??
  • ????//4.?epoll_wait??
  • ????//將新建立的連接添加到EPOLL的監聽中??
  • ????struct?epoll_event?event;??
  • ????event.data.fd?=?confd;??
  • ????event.events?=??EPOLLIN|EPOLLET;??
  • ????epoll_ctl(epollfd,?EPOLL_CTL_ADD,?confd,?&event);??
  • }??
  • ??
  • //讀取數據??
  • void?RecvData(int?fd)??
  • {??
  • ????int?ret;??
  • ????int?recvLen?=?0;??
  • ??????
  • ????memset(recvBuf,?0,?REVLEN);??
  • ????printf("RecvData?function\n");??
  • ??????
  • ????if(recvLen?!=?REVLEN)??
  • ????{??
  • ????????while(1)??
  • ????????{??
  • ????????????//recv數據??
  • ????????????ret?=?recv(fd,?(char?*)recvBuf+recvLen,?REVLEN-recvLen,?0);??
  • ????????????if(ret?==?0)??
  • ????????????{??
  • ????????????????recvLen?=?0;??
  • ????????????????break;??
  • ????????????}??
  • ????????????else?if(ret?<?0)??
  • ????????????{??
  • ????????????????recvLen?=?0;??
  • ????????????????break;??
  • ????????????}??
  • ????????????//數據接受正常??
  • ????????????recvLen?=?recvLen+ret;??
  • ????????????if(recvLen<REVLEN)??
  • ????????????{??
  • ????????????????continue;??
  • ????????????}??
  • ????????????else??
  • ????????????{??
  • ????????????????//數據接受完畢??
  • ????????????????printf("buf?=?%s\n",??recvBuf);??
  • ????????????????recvLen?=?0;??
  • ????????????????break;??
  • ????????????}??
  • ????????}??
  • ????}??
  • ??
  • ????printf("content?is?%s",?recvBuf);??
  • }?
  • 總結

    以上是生活随笔為你收集整理的socket编程 及select poll epoll示例的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。