select poll epoll 水平触发 边缘触发

# select

 

 

/*  select阻塞函数,多次还是需要while,在新建客户端方面有没有都一样
        因为accept多次也需要while
    但在判断客户端是否有数据到来方面
        使用了select就不需要创建多个线程或进程判断了,select可以批量判断
*/
#include <stdio.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    int lfd = socket(AF_INET, SOCK_STREAM, 0);
    if(lfd == -1)
    {
        perror("socket");
        exit(-1);
    }

    char *buf = "192.168.248.128";
    int ip;
    inet_pton(AF_INET, buf, &ip);

    struct sockaddr_in saddr;
    saddr.sin_addr.s_addr = ip;
    saddr.sin_port = htons(9999);
    saddr.sin_family = AF_INET;

    // 绑定
    int ret = bind(lfd, (struct sockaddr *) &saddr, sizeof(saddr));
    if(ret == -1)
    {
        perror("bind");
        exit(-1);
    }
    ret = listen(lfd, 5);
    if(ret == -1)
    {
        perror("listen");
        exit(-1);
    }
    fd_set readfds, tmp; // 因为select返回时,内核会修改set,为了能够实现多次监听,需要一个副本记录原始set
    FD_ZERO(&readfds);
    FD_SET(lfd, &readfds);
    int maxfd = lfd; // 需要监听的最大序号的描述符


    while(1)
    {
        tmp = readfds;
        ret = select(maxfd + 1, &tmp, NULL, NULL, NULL);
        if(ret == -1)
        {
            perror("select");
            exit(-1);
        }
        else if(ret == 0)
        {
            continue;
        }
        else
        {
            if(FD_ISSET(lfd, &tmp)) // 是否有新的客户端到达
            {
                struct sockadd_in client_addr;
                int client_addr_len = sizeof(client_addr);
                int cfd = accept(lfd, (struct sockaddr *) &client_addr, &client_addr_len);
                FD_SET(cfd, &readfds);
                maxfd = cfd > maxfd ? cfd : maxfd;
            }
            for(int i = lfd + 1; i < maxfd + 1; i++) // 已经到达的客户端是否写了数据到我的读缓冲区
            {
                if(FD_ISSET(i, &tmp)) // 如果我的读缓冲区有数据
                {
                    char readBuf[1024];
                    int read_len = read(i, readBuf, sizeof(readBuf)); // 读取数据
                    if(read_len == 0)
                    {
                        printf("客户端连接断开······");
                        close(i); // 既然关闭了连接,则close描述符
                        FD_CLR(i, &readfds); // 在监听集合中删除相应描述符
                    }
                    else if(read_len == -1)
                    {
                        perror("read");
                        exit(-1);
                    }
                    else
                    {
                        printf("recv info : %s\n", readBuf);
                        write(i, readBuf, strlen(readBuf) + 1);
                    }
                }

            }
        }


    }
    close(lfd);














    return 0;
}

 

# poll

 

 

#include <stdio.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <poll.h>
int main()
{
    int lfd = socket(AF_INET, SOCK_STREAM, 0);
    if(lfd == -1)
    {
        perror("socket");
        exit(-1);
    }

    char *buf = "192.168.248.128";
    int ip;
    inet_pton(AF_INET, buf, &ip);

    struct sockaddr_in saddr;
    saddr.sin_addr.s_addr = ip;
    saddr.sin_port = htons(9999);
    saddr.sin_family = AF_INET;

    // 绑定
    int ret = bind(lfd, (struct sockaddr *) &saddr, sizeof(saddr));
    if(ret == -1)
    {
        perror("bind");
        exit(-1);
    }
    ret = listen(lfd, 5);
    if(ret == -1)
    {
        perror("listen");
        exit(-1);
    }
    struct pollfd fds[1024]; // poll 是通过结构体数组
    for(int i = 0; i < 1024; i++)
    {
        fds[i].fd = -1;
        fds[i].events = POLLIN;
    }
    int cnt = 0;
    
    while(1)
    {
        ret = poll(fd, cnt + 1, -1);
        if(ret == -1)
        {
            perror("poll");
            exit(-1);
        }
        else if(ret == 0)
        {
            continue;
        }
        else
        {
            if(fds[0].revents & POLLIN) // 是否有新的客户端到达,用&是因为防止revents是多个状态的|
            {
                struct sockadd_in client_addr;
                int client_addr_len = sizeof(client_addr);
                int cfd = accept(lfd, (struct sockaddr *) &client_addr, &client_addr_len);
                int i;
                for(i = 1; i < 1024 && fds[i].fd != -1; i++);
                fds[i].fd = cfd;
                fds[i].events = POLLIN;
                cnt = i > cnt ? i : cnt;
            }
            for(int i = 0; i < cnt + 1; i++) // 已经到达的客户端是否写了数据到我的读缓冲区
            {
                if(fds[i].revents & POLLIN) // 如果我的读缓冲区有数据
                {
                    char readBuf[1024];
                    int read_len = read(i, readBuf, sizeof(readBuf)); // 读取数据
                    if(read_len == 0)
                    {
                        printf("客户端连接断开······");
                        close(i); // 既然关闭了连接,则close描述符
                        FD_CLR(i, &readfds); // 在监听集合中删除相应描述符
                    }
                    else if(read_len == -1)
                    {
                        perror("read");
                        exit(-1);
                    }
                    else
                    {
                        printf("recv info : %s\n", readBuf);
                        write(i, readBuf, strlen(readBuf) + 1);
                    }
                }

            }
        }


    }
    close(lfd);














    return 0;
}

 

# epoll

 

 

 

 

#include <stdio.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/epoll.h>
int main()
{
    int lfd = socket(AF_INET, SOCK_STREAM, 0);
    if(lfd == -1)
    {
        perror("socket");
        exit(-1);
    }

    char *buf = "192.168.248.128";
    int ip;
    inet_pton(AF_INET, buf, &ip);

    struct sockaddr_in saddr;
    saddr.sin_addr.s_addr = ip;
    saddr.sin_port = htons(9999);
    saddr.sin_family = AF_INET;

    // 绑定
    int ret = bind(lfd, (struct sockaddr *) &saddr, sizeof(saddr));
    if(ret == -1)
    {
        perror("bind");
        exit(-1);
    }
    ret = listen(lfd, 5);
    if(ret == -1)
    {
        perror("listen");
        exit(-1);
    }

    int efd = epoll_create(2000);
    struct epoll_event epevt;
    epevt.events = EPOLLIN;
    epevt.data.fd = lfd;
    epoll_ctl(efd, EPOLL_CTL_ADD, lfd, &epevt);



    struct epoll_event epevts[1024]; // 传出参数,用于返回到达事件的集合
    
    while(1)
    {

        ret = epoll_wait(efd, epevts, 1024, -1);
        if(ret == -1)
        {
            perror("epoll");
            exit(-1);
        }
        else if(ret == 0)
        {
            continue;
        }
        else
        {
            if(fds[0].revents & POLLIN) // 是否有新的客户端到达,用&是因为防止revents是多个状态的|
            {
                struct sockadd_in client_addr;
                int client_addr_len = sizeof(client_addr);
                int cfd = accept(lfd, (struct sockaddr *) &client_addr, &client_addr_len);
                int i;
                for(i = 1; i < 1024 && fds[i].fd != -1; i++);
                fds[i].fd = cfd;
                fds[i].events = POLLIN;
                cnt = i > cnt ? i : cnt;
            }
            for(int i = 0; i < ret; i++) // 已经到达的客户端是否写了数据到我的读缓冲区
            {
                if(epevts[i].data.fd == lfd)
                {
                    struct sockadd_in client_addr;
                    int client_addr_len = sizeof(client_addr);
                    int cfd = accept(lfd, (struct sockaddr *) &client_addr, &client_addr_len);
                    struct epoll_event epevt;
                    epevt.data.fd = cfd;
                    epevt.events = EPOLLIN;
                    epoll_ctl(efd, EPOLL_CTL_ADD, cfd, &epevt);
                }
                else // 如果我的读缓冲区有数据
                {
                    char readBuf[1024];
                    int read_len = read(epevts[i].data.fd, readBuf, sizeof(readBuf)); // 读取数据
                    if(read_len == 0)
                    {
                        printf("客户端连接断开······");
                        close(epevts[i].data.fd); // 既然关闭了连接,则close描述符
                        epoll_ctl(efd, EPOLL_CTL_DEL, epevts[i].data.fd, NULL);
                    }
                    else if(read_len == -1)
                    {
                        perror("read");
                        exit(-1);
                    }
                    else
                    {
                        printf("recv info : %s\n", readBuf);
                        write(epevts[i].data.fd, readBuf, strlen(readBuf) + 1);
                    }
                }

            }
        }


    }
    close(efd); // 关闭epoll的描述符
    close(lfd);
    





    return 0;
}

 # 水平触发、边缘触发

 

默认为水平触发

 

 

posted @ 2023-05-14 22:10  WTSRUVF  阅读(41)  评论(0编辑  收藏  举报