I/O多路转接之poll——基于TCP协议
1. 函數(shù)
a. 參數(shù):
(1)fds:是一個(gè)struct pollfd結(jié)構(gòu)類型的指針,指向用于存放需要檢測(cè)狀態(tài)的Socket描述符;
每當(dāng)調(diào)用這個(gè)函數(shù)之后,系統(tǒng)不會(huì)清空這個(gè)數(shù)組,操作起來比較方便;特別是對(duì)于socket連接比較多的情況下,在一定程度上可以提高處理的效率;這一點(diǎn)與select()函數(shù)不同,調(diào)用select()函數(shù)之后,select()函數(shù)會(huì)清空它所檢測(cè)的socket描述符集合,導(dǎo)致每次調(diào)用select()之前都必須把socket描述符重新加入到待檢測(cè)的集合中;因此,select()函數(shù)適合于只檢測(cè)一個(gè)socket描述符的情況,而poll()函數(shù)適合于大量socket描述符的情況;
fd:表示所要關(guān)心的文件描述符;
events:表示該文件描述符所關(guān)心的事件,這是一個(gè)輸入型參數(shù),要告訴操作系統(tǒng)這個(gè)文件描述符對(duì)應(yīng)的事件所關(guān)心的操作事件是什么,比如讀或?qū)?#xff1b;
revents:表示當(dāng)poll返回時(shí)告訴用戶什么操作事件是就緒的,比如如果POLLIN是就緒的,那么返回時(shí)revent的值就是POLLIN,告訴用戶fd事件的POLLIN是就緒的;是一個(gè)輸出型參數(shù)。
(2)nfds:標(biāo)記指針fds所指向的結(jié)構(gòu)體元素的總數(shù)量;
(3)timeout:poll函數(shù)調(diào)用阻塞的時(shí)間,單位:毫秒。(和select的一樣)
如果參數(shù)timeout設(shè)為:
INFTIM:select將一直被阻塞,直到某個(gè)文件描述符上發(fā)生了事件。
0:select將以非阻塞方式等,即檢測(cè)描述符集的狀態(tài)后立即返回,并不等待外部事件的發(fā)生。
大于0的值:poll()函數(shù)會(huì)阻塞timeout所指定的毫秒時(shí)間長度之后返回,如果在指定的時(shí)間段里沒有事件發(fā)生,select將超時(shí)返回0。
c. 返回值
(1)成功:則返回fds指針?biāo)赶虻膬?nèi)容中準(zhǔn)備好的讀、寫或出錯(cuò)狀態(tài)的那些socket描述符的總數(shù)量(返回值>0);
(2)poll函數(shù)調(diào)用失敗:返回-1,同時(shí)會(huì)自動(dòng)設(shè)置全局變量errno;;
(3)超過timeout時(shí)間,返回0。(沒有任何socket描述符準(zhǔn)備好讀、寫,或出錯(cuò))
2. poll和select對(duì)比
(1)不同:
select使用三個(gè)位圖來表示三個(gè)fdset的方式,poll使用一個(gè) pollfd的指針實(shí)現(xiàn)。
pollfd結(jié)構(gòu)包含了要監(jiān)視的event和發(fā)生的event,不再使用select“參數(shù)-值”傳遞的方式。
pollfd并沒有最大數(shù)量限制(但是數(shù)量過大后性能也是會(huì)下降)。?
(2)相同:
和select函數(shù)一樣,poll返回后,需要輪詢pollfd來獲取就緒的描述符。
從上面看,select和poll都需要在返回后,通過遍歷文件描述符來獲取已經(jīng)就緒的socket。事實(shí)上,同時(shí)連接的大量客戶端在一時(shí)刻可能只有很少的處于就緒狀態(tài),因此隨著監(jiān)視的描述符數(shù)量的增長,其效率也會(huì)線性下降。
3.代碼實(shí)現(xiàn)
//poll_server.c1?#include<stdio.h>2?#include<stdlib.h>3?#include<assert.h>4?#include<poll.h>5?#include<unistd.h>6?#include<sys/socket.h>7?#include<sys/types.h>8?#include<arpa/inet.h>9?#include<netinet/in.h>10?11?#define?_BACKLOG_?512?#define?_NUM_?1013?14?static?void?usage(const?char*?proc)15?{16?????printf("usage:%s?[ip]??[port]\n",proc);17?}18?static?int?startup(char*?ip,int?port)19?{20?????assert(ip);21?????//22?????int?sock=socket(AF_INET,SOCK_STREAM,0);23?????if(sock<0)24?????{25?????????perror("socket");26?????????exit(1);27?????}28?????//29?????struct?sockaddr_in?local;30?????local.sin_family=AF_INET;31?????local.sin_port=htons(port);32?????local.sin_addr.s_addr=inet_addr(ip);33?????//34?????if(bind(sock,(struct?sockaddr*)&local,sizeof(local))<0)35?????{36?????????perror("bind");37?????????exit(2);38?????}39?????if(listen(sock,_BACKLOG_)<0)40?????{41?????????perror("listen");42?????????exit(3);43?????}44?????return?sock;45?}46?int?main(int?argc,char*?argv[])47?{48?????if(argc!=3)49?????{50?????????usage(argv[0]);51?????????exit(1);52?????}53?????char*?ip=argv[1];54?????int?port=atoi(argv[2]);55?56?????int?listen_sock=startup(ip,port);57?58?????struct?sockaddr_in?client;59?????socklen_t?len=sizeof(client);60?61?????struct?pollfd?fds[_NUM_];62?????int?max_fd=1;//int?max_fd=fds[0].fd63?????int?_timeout=5000;64?????fds[0].fd=listen_sock;//why?locate65?????fds[0].events=POLLIN;66?????fds[0].revents=0;67?68?????size_t?i=1;69?????for(;i<_NUM_;i++)70?????{71?????????fds[i].fd=-1;72?????????fds[i].events=0;73?????????fds[i].revents=0;74?????}75?????while(1)76?????{77?????????switch(poll(fds,max_fd,_timeout))78?????????{79?????????????case?-1:80?????????????????perror("poll");81?????????????????break;82?????????????case?0:83?????????????????printf("timeout...\n");84?????????????????break;85?????????????default:86?????????????????{87?????????????????????i=0;88?????????????????????for(;i<_NUM_;++i)89?????????????????????{90?????????????????????????if((fds[i].fd==listen_sock)&&(fds[i].revents==POLLIN????))91?????????????????????????{92?????????????????????????????int?new_sock=accept(listen_sock,(struct?sockaddr????*)&client,&len);93?????????????????????????????if(new_sock<0)94?????????????????????????????{95?????????????????????????????????perror("accept");96?????????????????????????????????continue;97?????????????????????????????}98?????????????????????????????printf("get?a?new?connect...%d\n",new_sock);99?????????????????????????????for(i=0;i<_NUM_;i++) 100?????????????????????????????{ 101?????????????????????????????????if(fds[i].fd==-1) 102?????????????????????????????????{ 103?????????????????????????????????????fds[i].fd=new_sock; 104?????????????????????????????????????fds[i].events=POLLIN; 105?????????????????????????????????????max_fd++; 106?????????????????????????????????????break; 107?????????????????????????????????} 108?????????????????????????????} 109?????????????????????????????if(i==_NUM_) 110?????????????????????????????{ 111?????????????????????????????????close(new_sock); 112?????????????????????????????} 113?????????????????????????} 114?????????????????????????else?if((fds[i].fd>0)&&(fds[i].revents==POLLIN)) 115?????????????????????????{ 116?????????????????????????????char?buf[1024]; 117?????????????????????????????ssize_t?_s=read(fds[i].fd,buf,sizeof(buf)-1); 118?????????????????????????????if(_s>0) 119?????????????????????????????{ 120?????????????????????????????????//read?sucess 121?????????????????????????????????buf[_s]='\0'; 122?????????????????????????????????printf("client:%s\n",buf); 123?????????????????????????????} 124?????????????????????????????else?if(_s==0) 125?????????????????????????????{ 126?????????????????????????????????//client?shutdown 127?????????????????????????????????printf("client?shutdown...\n"); 128?????????????????????????????????// 129?????????????????????????????????struct?pollfd?tmp=fds[i]; 130?????????????????????????????????fds[i]=fds[max_fd-1]; 131?????????????????????????????????fds[max_fd-1]=tmp; 132?????????????????????????????????// 133?????????????????????????????????close(fds[max_fd-1].fd); 134?????????????????????????????????// 135? 136?????????????????????????????????fds[max_fd-1].fd=-1; 137?????????????????????????????????fds[max_fd-1].events=0; 138?????????????????????????????????fds[max_fd-1].revents=0; 139?????????????????????????????????//easy?ignore 140?????????????????????????????????--max_fd; 141?????????????????????????????} 142?????????????????????????????else 143?????????????????????????????{ 144?????????????????????????????????perror("read"); 145?????????????????????????????} 146?????????????????????????} 147?????????????????????????//normal?socket 148?????????????????????????else 149?????????????????????????{} 150?????????????????????} 151?????????????????} 152?????????????????break; 153?????????} 154?????} 155?????return?0; 156?}//poll_client.c1?#include<stdio.h>2?#include<stdlib.h>3?#include<string.h>4?#include<sys/types.h>5?#include<sys/socket.h>6?#include<netinet/in.h>7?#include<arpa/inet.h>8?#include<unistd.h>9?10?void?usage(const?char*?proc)11?{???12?????printf("%s?[ip]?[port]\n",proc);13?????exit(1);14?}15?int?main(int?argc,char*?argv[])16?{17?????if(argc!=3)18?????{19?????????usage(argv[0]);20?????????exit(1);21?????}22?????int?server_ip=inet_addr(argv[1]);23?????int?server_port=atoi(argv[2]);24?25?????int?client_sock=socket(AF_INET,SOCK_STREAM,0);26?????if(client_sock<0)27?????{28?????????perror("socket");29?????????exit(2);30?????}31?????struct?sockaddr_in?server;32?????server.sin_family=AF_INET;33?????server.sin_addr.s_addr=server_ip;34?????server.sin_port=htons(server_port);35?36?????if(connect(client_sock,(struct?sockaddr*)&server,sizeof(server))<0)37?????{38?????????perror("connect");39?????????exit(3);40?????}41?????char?buf[1024];42?????while(1)43?????{44?????????memset(buf,'\0',sizeof(buf));45?????????printf("Please?Input:?");46?????????fflush(stdout);47?????????fgets(buf,sizeof(buf)-1,stdin);48?????????if(send(client_sock,buf,sizeof(buf)-1,0)<0)49?????????{50?????????????perror("send");51?????????????continue;52?????????}53?????????ssize_t?_size=recv(client_sock,buf,sizeof(buf)-1,0);54?????????if(_size>0)55?????????{56?????????????buf[_size]='\0';57?????????????printf("server?receive:%s\n",buf);58?????????}59?????}60?????return?0;61?}//makefile1?.PHONY:all2?all:poll_server?poll_client3?poll_server:poll_server.c4?????gcc?-o?$@?$^5?poll_client:poll_client.c6?????gcc?-o?$@?$^7?.PHONY:clean8?clean:9?????rm?-f?poll_server?poll_client//start.sh1?#!/bin/bash2?3?service?iptables?stop4?./poll_server?192.168.163.128?8080運(yùn)行結(jié)果:
轉(zhuǎn)載于:https://blog.51cto.com/10707460/1794320
總結(jié)
以上是生活随笔為你收集整理的I/O多路转接之poll——基于TCP协议的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【项目 报错】 项目启动,内存溢出
- 下一篇: 源码lnmp