【网络编程】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[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等技术内容,点击立即学习:链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值