I/O多路转接之poll服务器
来源:互联网 发布:淘宝刷qq会员是真的吗 编辑:程序博客网 时间:2024/06/04 19:50
函数说明:
#include <poll.h> int poll(struct pollfd *fds, nfds_t nfds, int timeout);
参数说明:
fds:是一个struct pollfd结构类型的数组,用于存放需要检测其状态的Socket描述符;每当调用这个函数之后,系统不会清空这个数组,操作起来比较方便;特别是对于socket连接比较多的情况下,在一定程度上可以提高处理的效率;这一点与select()函数不同,调用select()函数之后,select()函数会清空它所检测的socket描述符集合,导致每次调用select()之前都必须把socket描述符重新加入到待检测的集合中;因此,select()函数适合于只检测一个socket描述符的情况,而poll()函数适合于大量socket描述符的情况;
nfds:nfds_t类型的参数,用于标记数组fds中的结构体元素的总数量;
timeout:是poll函数调用阻塞的时间,单位:毫秒;
返回值:
(1)大于0:数组fds中准备好读、写或出错状态的那些socket描述符的总数量;
(2)等于0:数组fds中没有任何socket描述符准备好读、写,或出错;此时poll超时,超时时间是timeout毫秒;换句话说,如果所检测的socket描述符上没有任何事件发生的话,那么poll()函数会阻塞timeout所指定的毫秒时间长度之后返回,如果timeout==0,那么poll() 函数立即返回而不阻塞,如果timeout==INFTIM,那么poll() 函数会一直阻塞下去,直到所检测的socket描述符上的感兴趣的事件发生是才返回,如果感兴趣的事件永远不发生,那么poll()就会永远阻塞下去;
(3)等于-1: poll函数调用失败,同时会自动设置全局变量errno;
pollfd结构 struct pollfd { int fd; /文件描述符/ short events; /* 等待的需要测试事件 */ short revents; /* 实际发生了的事件,也就是返回结果 */ };
poll函数可用的测试值
POLLIN 普通或优先级带数据可读
POLLRDNORM 普通数据可读
POLLRDBAND 优先级带数据可读
POLLPRI 高优先级数据可读
POLLOUT 普通数据可写
POLLWRNORM 普通数据可写
POLLWRBAND 优先级带数据可写
POLLERR 发生错误
POLLHUP 发生挂起
POLLNVAL 描述字不是一个打开的文件
poll服务器的优点
高效;文件描述符的个数没有上限,解决了select句柄有限的问题
缺点:
包含大量文件描述符的数组被整体复制于用户态和内核的地址空间之间,而不论这些文件描述符是否就绪,它的开销随着文件描述符数量的增加而线性增大。
//setver端代码#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <poll.h>#include <sys/time.h>#include <unistd.h>#include <sys/select.h>#include <netinet/in.h>#include <arpa/inet.h>#include <errno.h>#include <string.h>#define POLLFD_SIZE 1024static void usage(const char* proc){ printf("Usage:%s [local_ip] [local_port]\n", proc);}int startup(const char* _ip, int _port){ int sock = socket(AF_INET, SOCK_STREAM, 0); if(sock < 0) { perror("socket"); exit(2); } int opt = 1; setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); struct sockaddr_in local; local.sin_family = AF_INET; local.sin_port = htons(_port); local.sin_addr.s_addr = inet_addr(_ip); if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0) { perror("bind"); exit(3); } if(listen(sock, 10) < 0) { perror("listen"); exit(4); } return sock;}int main(int argc, char* argv[]){ if(argc != 3) { usage(argv[0]); return 1; } int listen_sock = startup(argv[1], atoi(argv[2])); struct pollfd pfd[POLLFD_SIZE]; pfd[0].fd = listen_sock; pfd[0].events = POLLIN; pfd[0].revents = 0; int timeout = 5000; int i = 1; for(; i<POLLFD_SIZE; i++) { pfd[i].fd = -1; } while(1) { switch(poll((struct pollfd *)&pfd, POLLFD_SIZE, timeout)) { case -1: perror("poll"); break; case 0: printf("timeout\n"); break; default: { int i=0; for(i=0; i<POLLFD_SIZE;++i) { if(i==0 && pfd[0].revents & POLLIN)//监听事件就绪 { struct sockaddr_in client; ssize_t len = sizeof(client); int new_sock = accept(listen_sock, (struct sockaddr*)&client, &len); if(new_sock < 0) { perror("accept"); continue; } printf("get a new client...[%s : %d]\n",\ inet_ntoa(client.sin_addr),ntohs(client.sin_port)); fflush(stdout); int j = 1; for(; j< POLLFD_SIZE; j++) { if(pfd[j].fd == -1) { pfd[j].fd = new_sock; pfd[j].events = POLLIN; break; } else if(j == POLLFD_SIZE) { printf("内存已满!"); return; } } } else if(i != 0)//读或写事件就绪 { if(pfd[i].revents & POLLIN) //read { char buf[1024]; ssize_t s = read(pfd[i].fd, buf, sizeof(buf)-1); if(s > 0) { buf[s] = 0; printf("client #%s\n", buf); fflush(stdout); pfd[i].events = POLLOUT; } else if(s == 0) { printf("client is quit\n"); close(pfd[i].fd); pfd[i].fd = -1; } else { perror("read"); close(pfd[i].fd); pfd[i].fd = -1; } } else if(pfd[i].revents & POLLOUT) //write { // const char*msg="HTTP/1.1 200 OK\r\n\r\n<html><br/><h1>hello poll</h1></html>"; // write(pfd[i].fd,msg,strlen(msg)); // pfd[i].events=POLLIN; char buf[1024]; printf("Please Enter# "); fflush(stdout); ssize_t s = read(0, buf, sizeof(buf)-1); if(s > 0) { buf[s-1] = 0; s = write(pfd[i].fd, buf, strlen(buf)); if(s > 0) { buf[s] = 0; printf(" server# : %s\n", buf); pfd[i].fd = POLLIN; continue; } else if(s == 0) { close(pfd[i].fd); pfd[i].fd = -1; break; } else { perror("write"); pfd[i].fd = -1; break; } } else if(s == 0) { printf("client is quit\n"); pfd[i].fd = -1; break; } else { perror("read"); pfd[i].fd = -1; break; } } }//else if }//for }//default }//switch }//while return 0;}
//client端代码#include <stdio.h>#include <sys/types.h>#include <sys/socket.h>#include <unistd.h>#include <errno.h>#include <arpa/inet.h>#include <stdlib.h>#include <string.h>#include <sys/stat.h>#include <fcntl.h>static void usage(const char* proc) //使用说明{ printf("Usage:%s [local_ip] [local_port]\n", proc);}//tcp_client server_ip server_portint main(int argc, char* argv[]){ if(argc != 3) { usage(argv[0]); return 1; } int sock = socket(AF_INET, SOCK_STREAM , 0); if(sock < 0) { perror("socket\n"); return 2; } struct sockaddr_in server; server.sin_family = AF_INET; server.sin_port = htons(atoi(argv[2])); server.sin_addr.s_addr = inet_addr(argv[1]); if(connect(sock, (struct sockaddr*)&server, sizeof(server)) < 0) { perror("connect\n"); return 3; } printf("connect success\n"); char buf[1024]; while(1) { printf("please Enter# \n"); fflush(stdout); ssize_t s = read(0, buf, sizeof(buf)-1); if(s > 0) { buf[s-1] = 0; write(sock, buf, strlen(buf)); s = read(sock, buf, sizeof(buf)-1); if(s > 0) { buf[s] = 0; printf("server echo# %s\n ", buf); } } } close(sock); return 0;}
运行结果:
代码还存在一点问题,稍后改正!
- I/O多路转接之poll服务器
- I/O多路转接之poll
- I/O多路转接之poll
- I/O多路转接之poll
- I/O多路转接之poll
- I/O多路转接之poll
- I/O多路转接之poll
- I/O多路转接之poll
- I/O多路转接之poll
- I/O多路转接之poll
- Linux【网络编程】——I/O多路转接之Poll服务器
- Linux下高级I/O多路转接之poll服务器
- I/O多路转接之select、poll、epoll
- I/O多路转接之poll 函数
- 【计算机网络】I/O多路转接之poll
- Linux—I/O多路转接之poll
- I/O多路转接之poll 函数
- I/O多路转接至poll
- Android如何修改listview条目与条目之间的分割线的高度与颜色
- <NOIP> 16 . P1055 ISBN号码
- 简易Launcher开发
- 五、State和生命周期
- SSM整合之拦截器
- I/O多路转接之poll服务器
- Redis Administration :
- java中获得一个类的类对象有哪些方式?
- 视频直播点播nginx-rtmp开发手册中文版
- matplotlib pyplot 显示中文
- Rabbitmq network partition的判定及恢复策略的选择
- 【腾讯Bugly干货分享】Android 进程保活招式大全
- kettle 7.1 集成 HDP2.6 写入HDFS 报错问题
- 利用Spring随时随地获得Request和Session