【网络编程】poll函数

简介: 【网络编程】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;
}
目录
相关文章
用MASM32按Time Protocol(RFC868)协议编写网络对时程序中的一些有用的函数代码
用MASM32按Time Protocol(RFC868)协议编写网络对时程序中的一些有用的函数代码
|
1月前
|
机器学习/深度学习 编解码
深度学习笔记(三):神经网络之九种激活函数Sigmoid、tanh、ReLU、ReLU6、Leaky Relu、ELU、Swish、Mish、Softmax详解
本文介绍了九种常用的神经网络激活函数:Sigmoid、tanh、ReLU、ReLU6、Leaky ReLU、ELU、Swish、Mish和Softmax,包括它们的定义、图像、优缺点以及在深度学习中的应用和代码实现。
125 0
深度学习笔记(三):神经网络之九种激活函数Sigmoid、tanh、ReLU、ReLU6、Leaky Relu、ELU、Swish、Mish、Softmax详解
|
1月前
|
机器学习/深度学习 数据可视化 算法
激活函数与神经网络------带你迅速了解sigmoid,tanh,ReLU等激活函数!!!
激活函数与神经网络------带你迅速了解sigmoid,tanh,ReLU等激活函数!!!
|
3月前
|
机器学习/深度学习 算法
神经网络中激活函数的重要性
【8月更文挑战第23天】
31 0
|
3月前
|
监控
【网络编程】select函数
【网络编程】select函数
65 0
|
3月前
|
机器学习/深度学习 Shell 计算机视觉
一文搞懂 卷积神经网络 卷积算子应用举例 池化 激活函数
这篇文章通过案例详细解释了卷积神经网络中的卷积算子应用、池化操作和激活函数,包括如何使用卷积算子进行边缘检测和图像模糊,以及ReLU激活函数如何解决梯度消失问题。
|
4月前
|
存储 Java Unix
(八)Java网络编程之IO模型篇-内核Select、Poll、Epoll多路复用函数源码深度历险!
select/poll、epoll这些词汇相信诸位都不陌生,因为在Redis/Nginx/Netty等一些高性能技术栈的底层原理中,大家应该都见过它们的身影,接下来重点讲解这块内容。
|
4月前
|
网络协议 安全 Java
Java中的网络编程:Socket编程详解
Java中的网络编程:Socket编程详解
|
4月前
|
Java API 网络安全
Java网络编程入门
Java网络编程入门
|
4月前
|
网络协议 安全 Java
Java中的网络编程:Socket编程详解
Java中的网络编程:Socket编程详解

热门文章

最新文章