- 1、poll函数
- 2、代码
- 3、socket常用函数出错处理封装
int poll(struct pollfd* fds,nfds_t nfds,int timeout);
struct pollfd
{
int fd; // 监听的文件描述符
short events; // 待监听文件描述符的对应事件
取值:POLLIN、POLLOUT、POLLERR
short revents; // 传入时0,如果满足对应事件的话,返回非0:POLLIN、POLLOUT、POLLERR
};
参数:
fds 监听文件描述符数组
nfds 监听数组的,实际有效监听个数
timeout 超时时长,单位:毫秒
-1阻塞等待
0立即返回,不堵塞进程
〉0 等待制定毫秒数,如当前系统时间精度不够毫秒,向上取值
返回值:
>0 返回满足对应监听事件的文件描述符总个数
0 没有满足监听条件的文件描述符
-1 设置errno
2、代码底层实现是一样,只是在select使用基础上进行了一点封装
优点:
自定数组结构,可以将,监听事件集合和返回事件集合分离
拓展监听上限,超出1024限制
缺点:
不能跨平台
无法直接定位满足监听事件的文件描述符,需要for
#include#include #include #include #include #include #include #include #include #include #include #include #include #include #include "socket_wrap.h" int main() { int i,j,listenfd,connfd,sockfd,maxi; int nready; ssize_t n; char buf[80],str[INET_ADDRSTRLEN]; socklen_t clien; struct pollfd client[1024]; struct sockaddr_in cliaddr,serv_addr; listenfd = Socket(AF_INET,SOCK_STREAM,0); int opt = 1; setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)); bzero(&serv_addr,sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); serv_addr.sin_port = htons(9999); Bind(listenfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr)); Listen(listenfd,128); client[0].fd = listenfd; // 要监听的第一个文件描述符,存入client[0] client[0].events = POLLIN; // listenfd 监听的普通事件 for(i=1;i<1024;i++) client[i].fd = -1; maxi = 0; while (1) { nready = poll(client,maxi+1,-1); if(client[0].revents & POLLIN) // listenfd有读事件就绪 { clien = sizeof(cliaddr); connfd = Accept(client[0].fd,(struct sockaddr*)&cliaddr,&clien); printf("客户端:%s:%dn", inet_ntop(AF_INET,&cliaddr.sin_addr.s_addr,str,sizeof(str)), ntohs(cliaddr.sin_port)); for(i=1;i<1024;i++) // i没机会++,因为break跳出了 { if(client[i].fd < 0) { client[i].fd = connfd; break; } } if(i == 1024) { perr_exit("too many clients"); } client[i].events = POLLIN; if(i>maxi) maxi = i; if(--nready == 0) continue; } for(i=1;i<=maxi;i++) { if((sockfd=client[i].fd)<0) { continue; } if(client[i].revents & POLLIN) { if((n=Read(sockfd,buf,sizeof(buf)))<0) { if(errno== ECONNRESET) // 收到RST标志 { printf("client[%d] aborted connectionn",i); Close(sockfd); client[i].fd = -1; //poll中不监控该文件描述符,直接置为-1即可, } else { perr_exit("read error"); } }else if(n==0) { Close(sockfd); client[i].fd = -1; printf("client[%d] aborted connection退出n",i); } else { for(j=0;j 3、socket常用函数出错处理封装 socket_wrap.h
#ifndef __WRAP_H_ #define __WRAP_H_ void perr_exit(const char* s); int Accept(int fd,struct sockaddr* sa,socklen_t* salenptr); int Bind(int fd,const struct sockaddr* sa,socklen_t salen); int Connect(int fd,const struct sockaddr* sa,socklen_t salen); int Listen(int fd,int backlog); int Socket(int family,int type,int protocol); ssize_t Read(int fd,void* ptr,size_t nbytes); ssize_t Write(int fd,const void* ptr,size_t nbytes); int Close(int fd); ssize_t Readn(int fd,void* vptr,size_t n); ssize_t Writen(int fd,const void* vptr,size_t n); static ssize_t my_read(int fd,char* ptr); ssize_t Readline(int fd,void* vptr,size_t maxlen); #endif // !__WRAP_H_socket_wrap.c
#include#include #include #include #include #include #include #include #include #include "socket_wrap.h" void perr_exit(const char* s) { perror(s); exit(1); } int Accept(int fd,struct sockaddr* sa,socklen_t* salenptr) { int n; again: if((n=accept(fd,sa,salenptr))<0) { if(errno == EConNABORTED || (errno==EINTR)) goto again; else perr_exit("accept error"); } return n; } int Bind(int fd,const struct sockaddr* sa,socklen_t salen) { int n; if((n=bind(fd,sa,salen))<0) { perr_exit("bind error"); } return n; } int Connect(int fd,const struct sockaddr* sa,socklen_t salen) { int n; if((n=connect(fd,sa,salen))<0) perr_exit("connect error"); return n; } int Listen(int fd,int backlog) { int n; if((n=listen(fd,n))<0) { perr_exit("listen error"); } return n; } int Socket(int family,int type,int protocol) { int n; if((n=socket(family,type,protocol))<0) perr_exit("socket error"); return n; } ssize_t Read(int fd,void* ptr,size_t nbytes) { ssize_t n; again: if((n=read(fd,ptr,nbytes))<0) { if(errno==EINTR) goto again; else return -1; } return n; } ssize_t Write(int fd,const void* ptr,size_t nbytes) { ssize_t n; if((n=write(fd,ptr,nbytes))<0) perr_exit("write error"); return n; } int Close(int fd) { int n; if((n=close(fd))<0) perr_exit("close error"); return n; } ssize_t Readn(int fd,void* vptr,size_t n) { size_t nleft; // unsigned int 剩余未读取字节数 ssize_t nread; // int 实际读到的字节数 char* ptr; ptr = vptr; nleft = n; while (nleft>0) { if((nread = read(fd,ptr,nleft))<0) { if(errno == EINTR) nread = 0; else return -1; } else if(nread == 0) break; nleft -= nread; ptr+=nread; } return n-nread; } ssize_t Writen(int fd,const void* vptr,size_t n) { size_t nleft; ssize_t nwritten; const char* ptr; ptr = vptr; nleft = n; while(nleft>0) { if((nwritten=write(fd,ptr,nleft))<=0) { if(nwritten<0 && errno==EINTR) nwritten = 0; else return -1; } nleft -= nwritten; ptr += nwritten; } return n; } static ssize_t my_read(int fd,char* ptr) { static int read_cnt; static char* read_ptr; static char read_buf[100]; if(read_cnt<=0) { again: if((read_cnt=read(fd,read_buf,sizeof(read_buf)))<0) { if(errno == EINTR) goto again; return -1; } else if(read_cnt == 0) return 0; read_ptr = read_buf; } read_cnt--; *ptr = *read_ptr++; return 1; } // 传出参数 vptr ssize_t Readline(int fd,void* vptr,size_t maxlen) { ssize_t n,rc; char c,*ptr; ptr = vptr; for(n=1;n



