立山 发表于 2024-7-15 21:48:15

【网络编程】poll函数

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;

    int maxfd;// 当前需要监听的最大的文件描述符
    int nready; // 返回的需要处理的个数
    int cfd;    // 通信描述符
    int i, maxi = 0;

    struct sockaddr_in clientsocket;
    socklen_t clilen;
    char buff; // 通信数据

    // 初始化有效的文件描述符数组
    for (int i = 0; i < POLLLEN; i++)
    {
      bzero(&connfd, sizeof(connfd));
      connfd.fd = -1;
    }

    maxfd = sfd;
    connfd.fd = sfd;
    connfd.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.revents == POLLIN)
            {
                // 有连接到来
                cfd = Accept(sfd, (struct sockaddr *)&clientsocket, &clilen);

                for (i = 0; i < POLLLEN; i++)
                {
                  if (connfd.fd == -1)
                  {
                        connfd.events = POLLIN;
                        connfd.fd = cfd;
                        maxi = i;
                        if (maxfd < cfd)
                        {
                            maxfd = cfd;
                        }
                        // 打印客户端的IP和PORT
                        char sIP;
                        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.fd == -1)
                {
                  continue;
                }
                if (connfd.revents == POLLIN)
                {
                  // 有数据发送过来
                  int n;
                  int sockfd = connfd.fd;
                  memset(buff, 0x00, sizeof(buff));
                  n = Read(sockfd, buff, sizeof(buff));
                  if (n < 0)
                  {
                        perror("read over");
                        close(sockfd);
                        bzero(&connfd, sizeof(bzero));
                        connfd.fd = -1; // 将connfd置为-1,表示该位置可用
                  }
                  else if (n == 0)
                  {
                        // printf("client is closed\n");
                        close(sockfd);
                        bzero(&connfd, sizeof(bzero));
                        connfd.fd = -1; // 将connfd置为-1,表示该位置可用
                  }
                  else
                  {
                        printf("[%d]:[%s]\n", n, buff);
                        for (i = 0; i < n; i++)
                        {
                            buff = toupper(buff);
                        }

                        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企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 【网络编程】poll函数