马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
poll和select的区别不大,主要是poll没有连接数限定,因为它用的链表实现
- #include <poll.h>
- int poll(struct pollfd *fds, nfds_t nfds, int timeout);
- struct pollfd {
- int fd; //要监控的文件描述符,如果fd为-1, 表示内核不再监控
- short events; //输入参数, 表示告诉内核要监控的事件, 读事件, 写事件, 异常事件
- short revents; //输出参数, 表示内核告诉应用程序有哪些文件描述符有事件发生
- };
- events/revents:
- POLLIN:可读事件
- POLLOUT: 可写事件
- POLLERR: 异常事件
- nfds: 告诉内核监控的范围, 具体是: 数组下标的最大值+1
- timeout:
- =0: 不阻塞, 立刻返回
- -1: 表示一直阻塞, 直到有事件发生
- >0: 表示阻塞时长, 在时长范围内若有事件发生会立刻返回;
- 如果超过了时长也会立刻返回
- 函数返回值:
- >0: 发生变化的文件描述符的个数
- =0: 没有文件描述符发生变化
- -1: 表示异常
复制代码 使用poll来监控多个文件描述符举行客户端通讯
代码:
- #include "socketwrap.h"
- #include <arpa/inet.h>
- #include <poll.h>
- #include <strings.h>
- #include <string.h>
- #include <ctype.h>
- #define POLLLEN 1024
- int main()
- {
- int sfd = Socket(AF_INET, SOCK_STREAM, 0);
- // 设置端口复用
- int opt = 1;
- setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int));
- struct sockaddr_in soaddr;
- bzero(&soaddr, sizeof(soaddr));
- soaddr.sin_family = AF_INET;
- soaddr.sin_port = htons(9999);
- soaddr.sin_addr.s_addr = htonl(INADDR_ANY);
- Bind(sfd, (struct sockaddr *)&soaddr, sizeof(soaddr));
- // 监听-listen
- Listen(sfd, 128);
- struct pollfd connfd[POLLLEN];
- int maxfd; // 当前需要监听的最大的文件描述符
- int nready; // 返回的需要处理的个数
- int cfd; // 通信描述符
- int i, maxi = 0;
- struct sockaddr_in clientsocket;
- socklen_t clilen;
- char buff[64]; // 通信数据
- // 初始化有效的文件描述符数组
- for (int i = 0; i < POLLLEN; i++)
- {
- bzero(&connfd[i], sizeof(connfd[i]));
- connfd[i].fd = -1;
- }
- maxfd = sfd;
- connfd[0].fd = sfd;
- connfd[0].events = POLLIN;
- while (1)
- {
- clilen = sizeof(clientsocket);
- bzero(&clientsocket, clilen);
- nready = poll(connfd, maxfd + 1, -1);
- if (nready < 0)
- {
- if (errno == EINTR) // 被信号中断
- {
- continue;
- }
- perror("poll error");
- break;
- }
- if (nready > 0)
- {
- if (connfd[0].revents == POLLIN)
- {
- // 有连接到来
- cfd = Accept(sfd, (struct sockaddr *)&clientsocket, &clilen);
- for (i = 0; i < POLLLEN; i++)
- {
- if (connfd[i].fd == -1)
- {
- connfd[i].events = POLLIN;
- connfd[i].fd = cfd;
- maxi = i;
- if (maxfd < cfd)
- {
- maxfd = cfd;
- }
- // 打印客户端的IP和PORT
- char sIP[16];
- memset(sIP, 0x00, sizeof(sIP));
- printf("client [%s:%d] connect\n", inet_ntop(AF_INET, &clientsocket.sin_addr.s_addr, sIP, sizeof(sIP)), htons(clientsocket.sin_port));
- break;
- }
- }
- if (i == POLLLEN)
- {
- close(cfd);
- printf("connect too much, server busy\n");
- continue;
- }
- if (--nready == 0)
- {
- continue;
- }
- }
- for (i = 1; i <= maxi; i++)
- {
- if (connfd[i].fd == -1)
- {
- continue;
- }
- if (connfd[i].revents == POLLIN)
- {
- // 有数据发送过来
- int n;
- int sockfd = connfd[i].fd;
- memset(buff, 0x00, sizeof(buff));
- n = Read(sockfd, buff, sizeof(buff));
- if (n < 0)
- {
- perror("read over");
- close(sockfd);
- bzero(&connfd[i], sizeof(bzero));
- connfd[i].fd = -1; // 将connfd[i]置为-1,表示该位置可用
- }
- else if (n == 0)
- {
- // printf("client is closed\n");
- close(sockfd);
- bzero(&connfd[i], sizeof(bzero));
- connfd[i].fd = -1; // 将connfd[i]置为-1,表示该位置可用
- }
- else
- {
- printf("[%d]:[%s]\n", n, buff);
- for (i = 0; i < n; i++)
- {
- buff[i] = toupper(buff[i]);
- }
- Write(sockfd, buff, n);
- }
- if (--nready <= 0)
- {
- break; // 注意这里是break,而不是continue, 应该是从最外层的while继续循环
- }
- }
- }
- }
- }
- close(sfd);
- return 0;
- }
复制代码 保举一个零声教育学习教程,个人以为老师讲得不错,分享给大家:[Linux,Nginx,ZeroMQ,MySQL,Redis,
fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,
TCP/IP,协程,DPDK等技术内容,点击立即学习:链接
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |