【Linux】多路 IO转接服务器 — poll
2018-01-11 16:27
309 查看
poll
#include <poll.h> int poll(struct pollfd *fds, nfds_t nfds, int timeout); struct pollfd { int fd; /* 文件描述符 */ short events; /* 监控的事件 */ short revents; /* 监控事件中满足条件返回的事件 */ }; POLLIN 普通或带外优先数据可读,即POLLRDNORM | POLLRDBAND POLLRDNORM 数据可读 POLLRDBAND 优先级带数据可读 POLLPRI 高优先级可读数据 POLLOUT 普通或带外数据可写 POLLWRNORM 数据可写 POLLWRBAND 优先级带数据可写 POLLERR 发生错误 POLLHUP 发生挂起 POLLNVAL 描述字不是一个打开的文件 nfds 监控数组中有多少文件描述符需要被监控 timeout 毫秒级等待 -1:阻塞等,#define INFTIM -1 Linux中没有定义此宏 0:立即返回,不阻塞进程 >0:等待指定毫秒数,如当前系统时间精度不够毫秒,向上取值
注:如果不再监控某个文件描述符时,可以把pollfd中,fd设置为-1,poll不再监控此pollfd,下次返回时,把revents设置为0。
ppoll
#define _GNU_SOURCE /* See feature_test_macros(7) */ #include <poll.h> int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts, const sigset_t *sigmask);
epoll 实现 C/S 模型
server:
#include<unistd.h> #include<stdlib.h> #include<stdio.h> #include<string.h> #include<errno.h> #include<ctype.h> #include<strings.h> #include<arpa/inet.h> #include<sys/types.h> #include<sys/socket.h> #include<sys/poll.h> #include"wrap.h" #define MAXLINE 80 #define SERV_PORT 8000 #define OPEN_MAX 1024 int main(int argc,char *argv[]) { int i,j,maxi,listenfd,connfd,sockfd; int nready; // 接收 poll 的返回值 ,记录满足监听事件的 fd 个数 ssize_t n; char buf[MAXLINE],str[INET_ADDRSTRLEN]; socklen_t clielen; struct pollfd client[OPEN_MAX]; struct sockaddr_in clieaddr,servaddr; listenfd = Socket(AF_INET,SOCK_STREAM,0); // 端口复用 int opt = 1; setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)); bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(SERV_PORT); servaddr.sin_addr.s_addr = htonl(INADDR_ANY); Bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr)); Listen(listenfd,128); client[0].fd = listenfd; // 要监听的第一个文件描述符 存入 client[0] client[0].events = POLLIN; // listenfd 监听普通读事件 for(i=1;i<OPEN_MAX;i++) // 用 -1 初始化 client[] 里的剩下元素,0 也是文件描述符,不能用 client[i].fd = -1; maxi = 0; // client 数组有效元素中最大元素下标 for( ; ; ) // 阻塞监听是否有客户端请求 { nready = poll(client,maxi+1,-1); // 阻塞监听是否有客户端连接 请求 if(client[0].revents & POLLIN) // listenfd 有读事件就绪 { clielen = sizeof(clieaddr); connfd = Accept(listenfd,(struct sockaddr*)&clieaddr,&clielen); // 接收客户端的请求 , Accept 不会阻塞 printf("received from %s at PORT %d\n", inet_ntop(AF_INET,&clieaddr.sin_addr.s_addr,str,sizeof(str)), ntohs(clieaddr.sin_port)); for(i=1;i<OPEN_MAX;i++) { if(client[i].fd < 0 ) { client[i].fd = connfd; // 找到 client[] 中空闲 位置,存放 accept 返回的 connfd break; } } if( i == OPEN_MAX ) // 达到了最大客户端数 perr_exit("too many client"); client[i].events = POLLIN; // 设置刚刚返回的 connfd,监控读事件 if( i>maxi ) maxi = i; // 更新 client[] 中的最大元素的下标 if(--nready <= 0 ) // 没有更多的就绪事件时,继续回到 poll 阻塞 continue; } for(i=1;i<=maxi;i++) // 前面if 没有满足,说明没有listenfd 满足。检测 client[] 看是哪个 connfd 就绪 { if((sockfd = client[i].fd)<0) continue; if( client[i].revents & POLLIN ) { if( (n = Read(sockfd,buf,MAXLINE)) <0 ) { // connection reset by client if( errno == ECONNRESET ) // 收到 RST 标志 { printf("client[%d] aborted connection\n",i); Close(sockfd); client[i].fd = -1; // poll 中不监控该文件描述符,直接置为 -1 即可,不用像select 那样移除 } else perr_exit("read error"); } else if(n == 0 ) // 说明客户端先关闭 { printf("client[%d] closed connection\n",i); Close(sockfd); client[i].fd = -1; } else { for(j=0;j<n;j++) buf[j] = toupper(buf[j]); Writen(sockfd,buf,n); } if( --nready <= 0 ) break; } } } return 0; }
client:
#include<unistd.h> #include<stdio.h> #include<string.h> #include<stdlib.h> #include<sys/types.h> #include<sys/socket.h> #include<arpa/inet.h> #include"wrap.h" #define MAXLINE 80 #define SERV_PORT 8000 int main(int argc,char*argv[]) { struct sockaddr_in servaddr; char buf[MAXLINE]; int sockfd,n; if( argc<2 ) { printf("./client IP\n"); exit(1); } sockfd = Socket(AF_INET,SOCK_STREAM,0); bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(SERV_PORT); inet_pton(AF_INET,argv[1],&servaddr.sin_addr); Connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr)); while(fgets(buf,MAXLINE,stdin) != NULL) { Write(sockfd,buf,strlen(buf)); n=Read(sockfd,buf,MAXLINE); if(n == 0) { printf("the other side has been closed\n"); break; } else Write(STDOUT_FILENO,buf,strlen(buf)); } Close(sockfd); return 0; }
相关文章推荐
- Linux下高级I/O多路转接之poll服务器
- 【Linux】多路 IO转接服务器 — select
- (五十四)高并发服务器——多路IO转接机制poll模型
- Linux高性能服务器之多路转接(2)---poll模型
- Linux【网络编程】——I/O多路转接之Poll服务器
- Linux下套接字详解(九)---poll模式下的IO多路复用服务器
- Linux网络编程(三)多路IO转接服务器
- Linux【网络编程】——I/O多路转接之Select服务器
- Linux下多路复用IO接口epoll/select/poll的区别
- Linux高性能服务器之多路转接(1)----select模型实现
- 【Linux网络编程】基于TCP协议 I/O多路转接(select) 的高性能回显服务器客户端模型
- [转载] Linux下多路复用IO接口 epoll select poll 的区别
- 多路转接服务器之poll
- LinuxIO多路复用之poll
- Linux【网络编程】——I/O多路转接之epoll服务器
- Linux下高级I/O多路转接之select服务器
- 【Linux】中多路转接之poll
- (五十三)高并发服务器——多路IO转接机制Select模型
- C/S通信---服务器IO多路复用模型之poll的使用
- Linux下多路复用IO接口epoll/select/poll的区别