首页 > 系统相关 >【Linux】poll函数

【Linux】poll函数

时间:2024-12-15 10:27:04浏览次数:12  
标签:函数 int soaddr fd Linux connfd poll sizeof buff

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;
}

标签:函数,int,soaddr,fd,Linux,connfd,poll,sizeof,buff
From: https://blog.csdn.net/qq_44653106/article/details/144467661

相关文章

  • 在Less中有哪些常用的函数?
    在Less中,存在许多实用的函数来帮助开发者更高效地编写和维护CSS代码。以下是一些常用的Less函数:字符串函数escape(@string):通过URL-encoding编码字符串。e(@string):对字符串进行转义处理。%(@string,values...):格式化字符串。replace('content','要进行替换的值',替换值):替......
  • 实现一个批量请求函数 multiRequest(urls, maxNum)
    在前端开发中,处理多个异步请求的一种常见需求是批量请求,并限制并发请求的数量以避免对服务器造成过大压力或浏览器资源耗尽。你可以使用Promise.all、Array.prototype.map和Array.prototype.reduce等方法来实现一个批量请求函数multiRequest,该函数接受一个URL数组和一个最......
  • 在非函数内写return语句,会有什么问题?
    在前端开发或任何编程语言中,return语句主要用于从函数中返回一个值或提前退出函数。如果你在非函数内(例如在全局作用域或代码块中)使用return语句,会导致语法错误或逻辑问题。以下是一些关键点:语法错误:在大多数编程语言中,包括JavaScript,return语句只能在函数体内使用。如果......
  • 考研数学二 2011-2024年 真题积累总结【多元函数与微分方程篇】_多元函数二阶导数_非
    文章目录多元函数1.多元函数二阶导数问题:f^''^~xy~(0,0)与f^''^~yx~(0,0)的计算(是否存在)2.多元函数非条件极值问题3.多元函数基础经典题已知对x的偏导数和对y的偏导数,求f(x,y)微分方程1.利用已知条件,构造微分方程,求y(x)的表达式2.给出关于f(x)的两个微分方程,求这个f......
  • 写一个方法记录函数运行的时间
    在前端开发中,记录一个函数运行的时间是一个常见的需求,通常用于性能调优和调试。你可以使用JavaScript提供的Date对象或者performanceAPI来实现这一功能。下面是两种方法的示例:方法一:使用Date对象Date对象可以获取当前的时间戳,通过计算函数执行前后的时间差,可以得到函......
  • Linux软件背光
    有时候显示器的亮度已经调到最低了,但还是太亮了。这时候就需要软件背光了。可以先试试redshift:redshift-b亮度亮度是0.1到1之间的数。完整文档:https://wiki.archlinux.org/title/redshift但不知道为什么我这里不管用。可能是因为我把内置显示器关了,只用外置显示器。如果r......
  • Linux挂载机械硬盘raid操作说明
    1.查看磁盘的信息,确认磁盘名一般可以根据磁盘的大小来确认是那个,如图所示,是/dev/md127lsblk 2.将磁盘的文件类型转化为exts,注意该操作将删除该磁盘所有的数据!!!!mkfs.ext4/dev/md127 3.挂在目录,如果不存在先创建目录,这里为/source挂在完成后使用df-h查看挂载信......
  • Linux学习相关网址
    Linux学习相关网址一、CentOS上的时间同步Linux-CentOS7上的时间同步-朱标-博客园(cnblogs.com)二、初始化相关CentOS7初始化环境搭建(包括系统安装、性能优化等)_没有梦想何必远方#-CSDN博客Centos7_系统初始优化配置-陶玉轩-博客园(cnblogs.com)CentOS......
  • 如何在 Linux 重启或启动时执行命令或脚本?
    在Linux的世界里,掌握在系统重启或启动时执行命令或脚本的技能,就如同拥有了一把开启自动化运维大门的神奇钥匙......
  • Nlog在windows运行正常,部署到Linux提示ystem.NullReferenceException: Object referen
    1.问题.net9webapplication,在Programe.cs文件中的NLog.LogManager.Configuration.Variables["configDir"]=env.ContentRootPath这句在Windows运行正常,部署到Ubuntu24.04就提示System.NullReferenceException:Objectreferencenotsettoaninstanceofanobject.......