多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國(guó)內(nèi)最全I(xiàn)T社區(qū)平臺(tái) 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁(yè) > php開源 > 綜合技術(shù) > TCP/IP網(wǎng)絡(luò)編程 基于Linux編程_這個(gè)優(yōu)于select的epoll

TCP/IP網(wǎng)絡(luò)編程 基于Linux編程_這個(gè)優(yōu)于select的epoll

來(lái)源:程序員人生   發(fā)布時(shí)間:2016-04-06 08:43:27 閱讀次數(shù):5243次

前言:關(guān)于并發(fā)服務(wù)器中的I/O復(fù)用實(shí)現(xiàn)方式,前面我們講過(guò)select的方式,但select的性能比較低,其實(shí)不合適以Web服務(wù)器端開發(fā)為主流的現(xiàn)代開發(fā)環(huán)境。因此就有了Linux下的epoll,BSD的kqueue,Solaris的/dev/poll和Windows的IOCP等復(fù)用技術(shù)。本章就來(lái)說(shuō)講Linux下的epoll技術(shù)。

epoll理解及利用

  • 基于select的I/O復(fù)用技術(shù)速度慢的緣由:
    1,調(diào)用select函數(shù)后常見的針對(duì)所有文件描寫符的循環(huán)語(yǔ)句。它每次事件產(chǎn)生需要遍歷所有文件描寫符,找動(dòng)身生變化的文件描寫符。(之前寫的示例沒(méi)加循環(huán))

    2,每次調(diào)用select函數(shù)時(shí)都需要向該函數(shù)傳遞監(jiān)視對(duì)象信息。即每次調(diào)用select函數(shù)時(shí)向操作系統(tǒng)傳遞監(jiān)視對(duì)象信息,至于為何要傳?是由于我們監(jiān)視的套接字變化的函數(shù),而套接字是操作系統(tǒng)管理的。(這個(gè)才是最耗效力的)

    注釋:基于這樣的緣由其實(shí)不是說(shuō)select就沒(méi)用了,在這樣的情況下就合適選用select:1,服務(wù)端接入者少 2,程序應(yīng)具有兼容性。

  • epoll是怎樣優(yōu)化select問(wèn)題的:
    1,每次產(chǎn)生事件它不需要循環(huán)遍歷所有文件描寫符,它把產(chǎn)生變化的文件描寫符單獨(dú)集中到了1起。

    2,僅向操作系統(tǒng)傳遞1次監(jiān)視對(duì)象信息,監(jiān)視范圍或內(nèi)容產(chǎn)生變化時(shí)只通知產(chǎn)生變化的事項(xiàng)。

  • 實(shí)現(xiàn)epoll時(shí)必要的函數(shù)和結(jié)構(gòu)體

    函數(shù):
    epoll_create:創(chuàng)建保存epoll文件描寫符的空間,該函數(shù)也會(huì)返回文件描寫符,所以終止時(shí),也要調(diào)用close函數(shù)。(創(chuàng)建內(nèi)存空間)

    epoll_ctl:向空間注冊(cè),添加或修改文件描寫符。(注冊(cè)監(jiān)聽事件)

    epoll_wait:與select函數(shù)類似,等待文件描寫符產(chǎn)生變化。(監(jiān)聽事件回調(diào))

    結(jié)構(gòu)體:
    struct epoll_event
    {
    __uint32_t events;
    epoll_data_t data;
    }

    typedef union epoll_data
    {
    void *ptr;
    int fd;
    __uinit32_t u32;
    __uint64_t u64;
    } epoll_data_t;

    基于epoll的回聲服務(wù)器

// // main.cpp // hello_server // // Created by app05 on 15⑴0⑴9. // Copyright (c) 2015年 app05. All rights reserved. // #include #include #include #include #include #include #include #define BUF_SIZE 100 #define EPOLL_SIZE 50 void error_handling(char *buf); int main(int argc, const char * argv[]) { int serv_sock, clnt_sock; struct sockaddr_in serv_adr, clnt_adr; socklen_t adr_sz; int str_len, i; char buf[BUF_SIZE]; //類似select的fd_set變量查看監(jiān)視對(duì)象的狀態(tài)變化,epoll_event結(jié)構(gòu)體將產(chǎn)生變化的文件描寫符單獨(dú)集中到1起 struct epoll_event *ep_events; struct epoll_event event; int epfd, event_cnt; if(argc != 2) { printf("Usage: %s", argv[0]); exit(1); } serv_sock = socket(PF_INET, SOCK_STREAM, 0); if(serv_sock == -1) error_handling("socket() error"); memset(&serv_adr, 0, sizeof(serv_adr)); serv_adr.sin_family = AF_INET; serv_adr.sin_addr.s_addr = htonl(INADDR_ANY); serv_adr.sin_port = htons(atoi(argv[1])); if(bind(serv_sock, (struct sockaddr *) &serv_adr, sizeof(serv_adr)) == -1) error_handling("bind() error"); if(listen(serv_sock, 5) == -1) error_handling("listen() error"); //創(chuàng)建文件描寫符的保存空間稱為“epoll例程” epfd = epoll_create(EPOLL_SIZE); ep_events = malloc(sizeof(struct epoll_event) *EPOLL_SIZE); //添加讀取事件的監(jiān)視(注冊(cè)事件) event.events = EPOLLIN; //讀取數(shù)據(jù)事件 event.data.fd = serv_sock; epoll_ctl(epdf, EPOLL_CTL_ADD, serv_sock, &event); while (1) { //響應(yīng)事件,返回產(chǎn)生事件的文件描寫符數(shù) event_cnt = epoll_wait(epfd, ep_events, EPOLL_SIZE, -1); //傳⑴時(shí),1直等待直到事件產(chǎn)生 if(event_cnt == -1) { puts("epoll_wait() error"); break; } //服務(wù)端套接字和客服端套接字 for (i = 0; i < event_cnt; i++) { if(ep_events[i].data.fd == serv_sock)//服務(wù)端與客服端建立連接 { adr_sz = sizeof(clnt_adr); clnt_sock = accept(serv_sock, (struct sockaddr *)&clnt_adr, &adr_sz); event.events = EPOLLIN; event.data.fd = clnt_sock; epoll_ctl(epfd, EPOLL_CTL_ADD, clnt_sock, &event); printf("connected client: %d ", clnt_sock); } else //連接以后傳遞數(shù)據(jù) { str_len = read(ep_events[i].data.fd, buf, BUF_SIZE); if(str_len == 0) { //刪除事件 epoll_ctl(epfd, EPOLL_CTL_DEL, ep_events[i].data.fd, NULL); close(ep_events[i].data.fd); printf("closed client: %d ", ep_events[i].data.fd); } else { write(ep_events[i].data.fd, buf, str_len); } } } } close(serv_sock); close(epfd); return 0; } void error_handling(char *message) { fputs(message, stderr); fputc(, stderr); exit(1); }

條件觸發(fā)和邊沿觸發(fā)

  • 甚么是條件觸發(fā)和邊沿觸發(fā)?它們是指事件響應(yīng)的方式,epoll默許是條件觸發(fā)的方式。條件觸發(fā)是指:只要輸入緩沖中有數(shù)據(jù)就會(huì)1直通知該事件,循環(huán)響應(yīng)epoll_wait。而邊沿觸發(fā)是指:輸入緩沖收到數(shù)據(jù)時(shí)僅注冊(cè)1次該事件,即便輸入緩沖中還留有數(shù)據(jù),也不會(huì)再進(jìn)行注冊(cè),只響應(yīng)1次。

  • 邊沿觸發(fā)相對(duì)條件觸發(fā)的優(yōu)點(diǎn):可以分離接收數(shù)據(jù)和處理數(shù)據(jù)的時(shí)間點(diǎn),從實(shí)現(xiàn)模型的角度看,邊沿觸發(fā)更有可能帶來(lái)高性能。

  • 將上面epoll實(shí)例改成邊沿觸發(fā):
    1,首先改寫 event.events = EPOLLIN | EPOLLET; (EPOLLIN:讀取數(shù)據(jù)事件 EPOLLET:邊沿觸發(fā)方式)

    2,邊沿觸發(fā)只響應(yīng)1次接收數(shù)據(jù)事件,所以要1次性全部讀取輸入緩沖中的數(shù)據(jù),那末就需要判斷甚么時(shí)候數(shù)據(jù)讀取完了?Linux聲明了1個(gè)全局的變量:int errno; (error.h中),它能記錄產(chǎn)生毛病時(shí)提供額外的信息。這里就能夠用它來(lái)判斷是不是讀取完數(shù)據(jù):

str_len = read(...); if(str_len < 0) { if(errno == EAGAIN) //讀取輸入緩沖中的全部數(shù)據(jù)的標(biāo)志 break; }

3,邊沿觸發(fā)方式下,以阻塞方式工作的read&write有可能會(huì)引發(fā)服務(wù)真?zhèn)€長(zhǎng)時(shí)間停頓。所以邊沿觸發(fā)1定要采取非阻塞的套接字?jǐn)?shù)據(jù)傳輸情勢(shì)。那末怎樣將套接字的read,write數(shù)據(jù)傳輸情勢(shì)修改成非阻塞模式呢?

//fd套接字文件描寫符,將此套接字?jǐn)?shù)據(jù)傳輸模式修改成非阻塞 void setnonblockingmode(int fd) { int flag = fcntl(fd, F_GETFL,0); //得到套接字原來(lái)屬性 fcntl(fd, F_SETFL, flag | O_NONBLOCK);//在原有屬性基礎(chǔ)上設(shè)置添加非阻塞模式 }
生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對(duì)您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 久久精品国产精品亚洲精品 | jizz老师| 一区二区三区在线免费观看视频 | 亚洲精品久久久久久久无 | 欧美性free hd| 久久久一区二区三区不卡 | 性欧美成人免费观看视 | 性做久久久久久久免费看 | 亚洲已满18点击进入在线观看 | 国产在线a | 国产福利乳摇在线播放 | 国产亚洲精品久久 | 波多野结衣四虎精品影库 | a级一级黄色片 | 国产性色强伦免费看视频 | 欧美性猛交xxxx免费 | 亚洲欧美日韩精品久久 | 中文有码在线观看 | 农村女人的一级毛片 | 最好免费高清视频在线看 | 婷婷在线五月 | 国产精品二区页在线播放 | jizz亚洲视频 | 欧美区国产区 | 久草中文字 | 红豆视频日本高清 | 国产一区免费在线观看 | 久久私人影院 | 亚洲乱码专区一区二区三区 | 亚洲欧美在线视频免费 | 成人小视频在线免费观看 | 亚洲 日本 欧美 日韩精品 | 欧美成人777 | 色偷偷亚洲女人天堂观看欧 | 亚洲色欲色欲综合网站 | 国内精品一区二区 | 娇小性色xxxxx中文 | 欧美淫 | 亚洲国产一区二区三区精品 | 被公侵犯肉体中文字幕一区二区 | 日韩在线专区 |