日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

socket编程 及select poll epoll示例

發(fā)布時(shí)間:2025/3/21 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 socket编程 及select poll epoll示例 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
[cpp] view plain copy
  • ??
  • 1、關(guān)于字節(jié)排序? ? 網(wǎng)際協(xié)議采用大端字節(jié)序,來(lái)傳輸多字節(jié)整數(shù)。? ? 系統(tǒng)提供了轉(zhuǎn)換的宏定義,如果主機(jī)與網(wǎng)際協(xié)議相同,則宏定義為空。

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

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

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

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

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

    ?? ? ? ? ?3)返回值? ? ? ? ? ? 成功:返回套接字符? ? ? ? ? ? 錯(cuò)誤:返回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)函數(shù)原型 int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen)
    ? ? ? ? 2)參數(shù): ? ?
    ? ? ? ? ? ? sockfd: socket 函數(shù)返回的套接字描述符
    ? ? ? ? ? ? servaddr : 服務(wù)器的IP和端口
    ? ? ? ? ? ? addrlen: 長(zhǎng)度(sizeof(servaddr))
    ? ? ? ? 3)返回值
    ? ? ? ? ? ? 成功:0
    ? ? ? ? ? ? 錯(cuò)誤:返回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)函數(shù)原型 int bind(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen)
    ? ? ? ? 2)參數(shù): ? ?
    ? ? ? ? ? ? sockfd: socket 函數(shù)返回的套接字描述符
    ? ? ? ? ? ? servaddr : 服務(wù)器的IP和端口
    ? ? ? ? ? ? addrlen: 長(zhǎng)度(sizeof(servaddr))
    ? ? ? ? 3)返回值
    ? ? ? ? ? ? 成功:0
    ? ? ? ? ? ? 錯(cuò)誤:返回INVALID_SOCKET(-1)
    ? ? ? ? ? ??
    ? ? d..listen
    ? ? ? ? 1)函數(shù)原型 int listen(int sockfd, int backlog)
    ? ? ? ? 2)參數(shù): ? ?
    ? ? ? ? ? ? sockfd: socket 函數(shù)返回的套接字描述符
    ? ? ? ? ? ? backlog : 內(nèi)核中套接字排隊(duì)的最大個(gè)數(shù)
    ? ? ? ? 3)返回值
    ? ? ? ? ? ? 成功:0
    ? ? ? ? ? ? 錯(cuò)誤:返回INVALID_SOCKET
    ? ? ? ? ? ? ? ??
    ? ? e..accept
    ? ? ? ? 1)函數(shù)原型 int accept(int sockfd, const struct sockaddr *servaddr, socklen_t *addrlen)
    ? ? ? ? 2)參數(shù): ? ?
    ? ? ? ? ? ? sockfd: socket 函數(shù)返回的套接字描述符


    ? ? ? ? 3)返回值
    ? ? ? ? ? ? servaddr : 客戶進(jìn)程的IP和端口(可設(shè)為null)
    ? ? ? ? ? ? addrlen: 長(zhǎng)度(sizeof(servaddr))(可設(shè)為null)
    ? ? ? ? ? ? 成功:從監(jiān)聽(tīng)套接字返回已連接套接字
    ? ? ? ? ? ? 錯(cuò)誤:
    ? ? ? ? ? ? 如果對(duì)客戶信息不感興趣,后兩個(gè)參數(shù)可以置空。

    ? ? ? ? 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 事件分派機(jī)制來(lái)看,使用 select()是不合適的,因?yàn)樗С值牟l(fā)連接數(shù)有限(通
    ? ? 常在 1024 個(gè)以內(nèi))。如果考慮性能,poll()也是不合適的,盡管它可以支持的較高的 TCP 并發(fā)
    ? ? 數(shù),但是由于其采用“輪詢”機(jī)制,當(dāng)并發(fā)數(shù)較高時(shí),其運(yùn)行效率相當(dāng)?shù)?并可能存在 I/O 事
    ? ? 件分派不均,導(dǎo)致部分 TCP 連接上的 I/O 出現(xiàn)“饑餓”現(xiàn)象。而如果使用 epoll 或 AIO,則沒(méi)
    ? ? 有上述問(wèn)題(早期 Linux 內(nèi)核的 AIO 技術(shù)實(shí)現(xiàn)是通過(guò)在內(nèi)核中為每個(gè) I/O 請(qǐng)求創(chuàng)建一個(gè)線程來(lái)
    ? ? 實(shí)現(xiàn)的,這種實(shí)現(xiàn)機(jī)制在高并發(fā) TCP 連接的情形下使用其實(shí)也有嚴(yán)重的性能問(wèn)題。但在最新的
    ? ? Linux 內(nèi)核中,AIO 的實(shí)現(xiàn)已經(jīng)得到改進(jìn))。
    ? ? 支持一個(gè)進(jìn)程打開(kāi)大數(shù)目的 socket 描述符(FD)select 最不能忍受的是一個(gè)進(jìn)程所打開(kāi)的
    ? ? FD 是有一定限制的,由 FD_SETSIZE 設(shè)置,默認(rèn)值是 2048。對(duì)于那些需要支持的上萬(wàn)連接數(shù)目
    ? ? 的 IM 服務(wù)器來(lái)說(shuō)顯然太少了。
    ? ? 這時(shí)候你一是可以選擇修改這個(gè)宏然后重新編譯內(nèi)核,不過(guò)資料
    ? ? 也同時(shí)指出這樣會(huì)帶來(lái)網(wǎng)絡(luò)效率的下降,二是可以選擇多進(jìn)程的解決方案(傳統(tǒng)的 Apache 方
    ? ? 案),不過(guò)雖然 linux 上面創(chuàng)建進(jìn)程的代價(jià)比較小,但仍舊是不可忽視的,加上進(jìn)程間數(shù)據(jù)同步
    ? ? 遠(yuǎn)比不上線程間同步的高效,所以也不是一種完美的方案。不過(guò) epoll 則沒(méi)有這個(gè)限制,它所
    ? ? 支持的 FD 上限是最大可以打開(kāi)文件的數(shù)目,這個(gè)數(shù)字一般遠(yuǎn)大于 2048,舉個(gè)例子,在 1GB 內(nèi)存
    ? ? 的機(jī)器上大約是 10 萬(wàn)左右,具體數(shù)目可以 cat /proc/sys/fs/file-max 察看,一般來(lái)說(shuō)這個(gè)數(shù)
    ? ? 目和系統(tǒng)內(nèi)存關(guān)系很大。
    ? ? ******************************************************************/ ? ? ? ?
    5. select函數(shù)
    ? ? 1)函數(shù)原型 int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);
    ? ? 2)參數(shù): ? ?
    ? ? ? ? sockfd: socket 函數(shù)返回的套接字描述符
    ? ? ? ? readfds : 讀描述符集合
    ? ? ? ? writefds: 寫(xiě)描述符集合
    ? ? ? ? errorfds: 錯(cuò)誤描述符集合
    ? ? ? ? timeout: ?超時(shí)
    ? ? 3)返回值
    ? ? ? ? 成功:返回值 0:無(wú) >0:描述符就緒的總位數(shù)
    ? ? ? ? 錯(cuò)誤:返回INVALID_SOCKET(-1)
    ? ? 4)包含頭文件: include <sys/select.h> include <sys/time.h>
    ? ? 5)示例
    [cpp] view plain copy
  • /*?實(shí)現(xiàn)功能:通過(guò)select處理多個(gè)socket?
  • ?*?監(jiān)聽(tīng)一個(gè)端口,監(jiān)聽(tīng)到有鏈接時(shí),添加到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];??
  • ??
  • //當(dāng)前的連接數(shù)??
  • int?currentClient?=?0;???
  • ??
  • //數(shù)據(jù)接受?buf??
  • #define?REVLEN?10??
  • char?recvBuf[REVLEN];??
  • //顯示當(dāng)前的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");??
  • ??????
  • ????????//讀取數(shù)據(jù)??
  • ????????for(i=0;?i<BACKLOG;?i++)??
  • ????????{??
  • ????????????if(client[i].fd>0?&&?FD_ISSET(client[i].fd,?&readfds))??
  • ????????????{??
  • ????????????????if(recvLen?!=?REVLEN)??
  • ????????????????{??
  • ????????????????????while(1)??
  • ????????????????????{??
  • ????????????????????????//recv數(shù)據(jù)??
  • ????????????????????????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;??
  • ????????????????????????}??
  • ????????????????????????//數(shù)據(jù)接受正常??
  • ????????????????????????recvLen?=?recvLen+ret;??
  • ????????????????????????if(recvLen<REVLEN)??
  • ????????????????????????{??
  • ????????????????????????????continue;??
  • ????????????????????????}??
  • ????????????????????????else??
  • ????????????????????????{??
  • ????????????????????????????//數(shù)據(jù)接受完畢??
  • ????????????????????????????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;??
  • }??
  • ??
  • //顯示當(dāng)前的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函數(shù)
    ? ? 1)函數(shù)原型 int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);
    ? ? 2)參數(shù): ? ?
    ? ? ? ? sockfd: socket 函數(shù)返回的套接字描述符
    ? ? ? ? readfds : 讀描述符集合
    ? ? ? ? writefds: 寫(xiě)描述符集合
    ? ? ? ? errorfds: 錯(cuò)誤描述符集合
    ? ? ? ? timeout: ?超時(shí)
    ? ? 3)返回值
    ? ? ? ? 成功:返回值 0:無(wú) >0:描述符就緒的總位數(shù)
    ? ? ? ? 錯(cuò)誤:返回INVALID_SOCKET(-1)
    ? ? 4)包含頭文件: include <sys/select.h> include <sys/time.h>

    ? ? 5) 示例

    [cpp] view plain copy
  • /*?實(shí)現(xiàn)功能:通過(guò)poll,?處理多個(gè)socket?
  • ?*?監(jiān)聽(tīng)一個(gè)端口,監(jiān)聽(tīng)到有鏈接時(shí),添加到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??
  • ??
  • //當(dāng)前的連接數(shù)??
  • int?currentClient?=?0;???
  • ??
  • //數(shù)據(jù)接受?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;??
  • ????????}??
  • ??????
  • ????????//讀取數(shù)據(jù)??
  • ????????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數(shù)據(jù)??
  • ????????????????????????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;??
  • ????????????????????????}??
  • ????????????????????????//數(shù)據(jù)接受正常??
  • ????????????????????????recvLen?=?recvLen+ret;??
  • ????????????????????????if(recvLen<REVLEN)??
  • ????????????????????????{??
  • ????????????????????????????continue;??
  • ????????????????????????}??
  • ????????????????????????else??
  • ????????????????????????{??
  • ????????????????????????????//數(shù)據(jù)接受完畢??
  • ????????????????????????????printf("buf?=?%s\n",??recvBuf);??
  • ????????????????????????????//close(client[i].fd);??
  • ????????????????????????????//client[i].fd?=?-1;??
  • ????????????????????????????recvLen?=?0;??
  • ????????????????????????????break;??
  • ????????????????????????}??
  • ????????????????????}??
  • ????????????????}??
  • ????????????}??
  • ????????}??
  • ????}??
  • ??
  • ????return?0;??
  • }??

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


    ? ? ? ? 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 不僅會(huì)告訴應(yīng)用程序有I/0 事件到來(lái),還會(huì)告訴應(yīng)用程序相關(guān)的信息,這些信息是應(yīng)用程序填充的,因此根據(jù)這些信息應(yīng)用程序就能直接定位到事件,而不必遍歷整個(gè)FD 集合。
    ? ? ? ? int res = epoll_wait(epfd, events, 20, 120);
    ? ? ? ? for (int i = 0; i < res;i++)
    ? ? ? ? {
    ? ? ? ? ? ? handleEvent(events[n]);
    ? ? ? ? }
    ? ? ? ? 5. Epoll 關(guān)鍵數(shù)據(jù)結(jié)構(gòu)
    ? ? ? ? 前面提到 Epoll 速度快和其數(shù)據(jù)結(jié)構(gòu)密不可分,其關(guān)鍵數(shù)據(jù)結(jié)構(gòu)就是:
    ? ? ? ? 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;
    ? ? ? ??
    ? ? ? ? 可見(jiàn) epoll_data 是一個(gè) union 結(jié)構(gòu)體 , 借助于它應(yīng)用程序可以保存很多類型的信息 :fd 、指針等等。有了它,應(yīng)用程序就可以直接定位目標(biāo)了。
    ? ? ? ? 6. 使用 Epoll
    ? ? ? ? 既然 Epoll 相比 select 這么好,那么用起來(lái)如何呢?會(huì)不會(huì)很繁瑣啊 … 先看看下面的三個(gè)函數(shù)吧,就知道 Epoll 的易用了。
    ? ? ? ? ?
    ? ? ? ? int epoll_create(int size);
    ? ? ? ? 生成一個(gè) Epoll 專用的文件描述符,其實(shí)是申請(qǐng)一個(gè)內(nèi)核空間,用來(lái)存放你想關(guān)注的 socket fd 上是否發(fā)生以及發(fā)生了什么事件。 size 就是你在這個(gè) Epoll fd 上能關(guān)注的最大 socket fd 數(shù),大小自定,只要內(nèi)存足夠。
    ? ? ? ??
    ? ? ? ? int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event );
    ? ? ? ? 控制某個(gè) Epoll 文件描述符上的事件:注冊(cè)、修改、刪除。其中參數(shù) epfd 是 epoll_create() 創(chuàng)建 Epoll 專用的文件描述符。相對(duì)于 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 事件的發(fā)生;參數(shù)說(shuō)明:
    ? ? ? ? epfd: 由 epoll_create() 生成的 Epoll 專用的文件描述符;
    ? ? ? ? epoll_event: 用于回傳代處理事件的數(shù)組;
    ? ? ? ? maxevents: 每次能處理的事件數(shù);
    ? ? ? ? timeout: 等待 I/O 事件發(fā)生的超時(shí)值,單位 ms
    ? ? ? ? 返回發(fā)生事件數(shù)。
    ? ? ? ? 相對(duì)于 select 模型中的 select 函數(shù)。
    ? ? ? ??
    [cpp] view plain copy
  • /*?實(shí)現(xiàn)功能:通過(guò)epoll,?處理多個(gè)socket?
  • ?*?監(jiān)聽(tīng)一個(gè)端口,監(jiān)聽(tīng)到有鏈接時(shí),添加到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??
  • ??
  • //當(dāng)前的連接數(shù)??
  • int?currentClient?=?0;???
  • ??
  • //數(shù)據(jù)接受?buf??
  • #define?REVLEN?10??
  • char?recvBuf[REVLEN];??
  • ??
  • //EPOLL相關(guān)???
  • //epoll描述符??
  • int?epollfd;??
  • //事件數(shù)組??
  • 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;??
  • ????????}??
  • ??????????
  • ????????//直接獲取了事件數(shù)量,給出了活動(dòng)的流,這里是和poll區(qū)別的關(guān)鍵??
  • ????????int?n?=?0;??
  • ????????for(n=0;?n<ret;?n++)??
  • ????????{??
  • ????????????//錯(cuò)誤退出??
  • ????????????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;??
  • }??
  • ??
  • /**************************************************?
  • 函數(shù)名:AcceptConn?
  • 功能:接受客戶端的鏈接?
  • 參數(shù):srvfd:監(jiān)聽(tīng)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的監(jiān)聽(tīng)中??
  • ????struct?epoll_event?event;??
  • ????event.data.fd?=?confd;??
  • ????event.events?=??EPOLLIN|EPOLLET;??
  • ????epoll_ctl(epollfd,?EPOLL_CTL_ADD,?confd,?&event);??
  • }??
  • ??
  • //讀取數(shù)據(jù)??
  • void?RecvData(int?fd)??
  • {??
  • ????int?ret;??
  • ????int?recvLen?=?0;??
  • ??????
  • ????memset(recvBuf,?0,?REVLEN);??
  • ????printf("RecvData?function\n");??
  • ??????
  • ????if(recvLen?!=?REVLEN)??
  • ????{??
  • ????????while(1)??
  • ????????{??
  • ????????????//recv數(shù)據(jù)??
  • ????????????ret?=?recv(fd,?(char?*)recvBuf+recvLen,?REVLEN-recvLen,?0);??
  • ????????????if(ret?==?0)??
  • ????????????{??
  • ????????????????recvLen?=?0;??
  • ????????????????break;??
  • ????????????}??
  • ????????????else?if(ret?<?0)??
  • ????????????{??
  • ????????????????recvLen?=?0;??
  • ????????????????break;??
  • ????????????}??
  • ????????????//數(shù)據(jù)接受正常??
  • ????????????recvLen?=?recvLen+ret;??
  • ????????????if(recvLen<REVLEN)??
  • ????????????{??
  • ????????????????continue;??
  • ????????????}??
  • ????????????else??
  • ????????????{??
  • ????????????????//數(shù)據(jù)接受完畢??
  • ????????????????printf("buf?=?%s\n",??recvBuf);??
  • ????????????????recvLen?=?0;??
  • ????????????????break;??
  • ????????????}??
  • ????????}??
  • ????}??
  • ??
  • ????printf("content?is?%s",?recvBuf);??
  • }?
  • 總結(jié)

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

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。