DEV Community

shuai991102
shuai991102

Posted on

epoll实现并发服务器代码

select/poll/epoll区别?

select:

        1、select监听的最大文件描述符是1024个;

        2、select需要反复构造表,反复从用户空间向内核空间拷贝表,效率低

        3、当数据准备好后,select需要再次遍历表,找出准备好的文件描述符,效率低

poll:

        1、poll监听的文件描述符没有限制

        2、poll不需要反复构造表,不需要反复拷贝表,效率高

        3、当数据准备好之后,poll需要遍历表,找出准备好的文件描述符,效率低

epoll:

        1、epoll监听的文件描述符没有限制

        2、epoll不需要反复构造表,不需要反复拷贝表,效率高

        3、当数据准备好之后,epoll直接能够找出准备好的文件描述符,不需要遍历表,效率高。
Enter fullscreen mode Exit fullscreen mode
#include "c.h"
#define ERR_MSG(msg)                          \
    do                                        \
    {                                         \
        fprintf(stderr, "line:%d", __LINE__); \
        perror(msg);                          \
    } while (0)
#define IP "192.168.250.100"
#define PORT 6666
#define BUFLEN 128
int deal_cli_msg(int newfd, struct sockaddr_in cin);

// 回收僵尸进程
void handler(int sig)
{
    while (waitpid(-1, NULL, WNOHANG) > 0)
        ;
}

int main(int argc, const char *argv[])
{
    char buf[BUFLEN];
    // 捕获17号 SIGCHLD信号,回收僵尸进程
    __sighandler_t s = signal(17, handler);
    if (SIG_ERR == s)
    {
        ERR_MSG("signal");
        return -1;
    }
    // 创建流式套接字
    int sfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sfd < 0)
    {
        ERR_MSG("socket");
        return -1;
    }
    printf("sfd=%d\n", sfd);
    // 允许端口快速重用
    int reuse = 1;
    if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
    {
        ERR_MSG("setsockopt");
        return -1;
    }
    printf("允许端口快速重用成功\n");

    // 填充地址信息结构体
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(PORT);
    sin.sin_addr.s_addr = inet_addr(IP);
    // 将ip和端口绑定到套接字上
    if (bind(sfd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
    {
        ERR_MSG("bind");
        return -1;
    }
    printf("ip绑定套接字成功__%d__\n", __LINE__);
    // 将套接字设置为可监听状态
    if (listen(sfd, 128) < 0)
    {
        ERR_MSG("listen");
        return -1;
    }
    printf("将套接字设置为可监听状态成功__%d__\n", __LINE__);
    // 存储连接成功的客户端地址信息
    struct sockaddr_in cin;
    socklen_t addrlen = sizeof(cin);
    int newfd = -1;
    int epfd,epct,i,ret;
    struct epoll_event event;       //定义epoll 事件
    struct epoll_event events[20];  //定义epoll 事件集合
    epfd = epoll_create(1); // 创建epoll 的fd //红黑树根节点

    event.data.fd = sfd;           //填充事件的fd
    event.events = EPOLLIN | EPOLLET;   //填充 事件类型 
    epoll_ctl(epfd,EPOLL_CTL_ADD,sfd,&event);  //把serverFd(监听FD)注册到epfd中


    while(1){

        epct = epoll_wait(epfd,events,20,-1); // 等待事件到来,阻塞模式 
        for(i=0;i<epct;i++){  //根据epoll返回的值来查询事件

            if(events[i].data.fd == sfd){ // 如果事件的fd是监听fd,调用accept处理
                newfd = accept(events[i].data.fd,(struct sockaddr *)&cin,&addrlen);
                event.data.fd = newfd;
                event.events = EPOLLIN | EPOLLET;
                epoll_ctl(epfd,EPOLL_CTL_ADD,newfd,&event);
                }
            else {   //如果不是serverFd,应是client数据事件,调用读数据

                memset(buf,0,BUFLEN);
                ret = read(events[i].data.fd,buf,BUFLEN);
                if(ret <=0){ //客户端断开 
                    printf("connect disconnected\n");
                    close(events[i].data.fd); //关闭文件描述符
                    epoll_ctl(epfd,EPOLL_CTL_DEL,events[i].data.fd,&event); //删除监听的客户端fd
                    continue;
                }
            }
        }
    }
    // 关闭进程的所有的文件描述符
    for (i = 0; i < getdtablesize(); i++)
    {
        close(i);
    }
    return 0;
}
Enter fullscreen mode Exit fullscreen mode

AWS GenAI LIVE image

Real challenges. Real solutions. Real talk.

From technical discussions to philosophical debates, AWS and AWS Partners examine the impact and evolution of gen AI.

Learn more

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay