我是靠谱客的博主 俭朴小松鼠,最近开发中收集的这篇文章主要介绍一个epoll的ET模式下的非阻塞的服务端小用例,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

后续知识会进行整理

代码

/** echo server
*   Time: 2021-12-02
*   Author: LH
*   code: --utf8--
*/

#ifdef ____Win32
#else
/* network io */
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <poll.h>

/* linux */
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

/* C */
#include <string.h>
#include <stdio.h>

#define SERVERPORT 3119

int main() {
    /** Create listening sockets
    */
    int listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if (listenfd == -1) {
        printf("socket error n");
        return -1;
    }
    /* Set reuse IP and port number */
    int on = 1;
    setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on));
    setsockopt(listenfd, SOL_SOCKET, SO_REUSEPORT, (char *)&on, sizeof(on));

    /* Set feizuse */
    int oldSocketFlag = fcntl(listenfd, F_GETFL, 0);
    int newSocketFlag = oldSocketFlag | O_NONBLOCK;
    if (fcntl(listenfd, F_SETFL, newSocketFlag) == -1) {
        close(listenfd);
        printf("fcntl error n");
        return -1;
    }
    /* Initializing the server */
    struct sockaddr_in bindaddr;
    bindaddr.sin_family = AF_INET;
    bindaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    bindaddr.sin_port = htons(SERVERPORT);

    if (bind(listenfd, (struct sockaddr *) &bindaddr, sizeof(bindaddr)) == -1) {
        printf("bind error n");
        close(listenfd);
        return -1;
    } 
    /* Start Listening */
    if (listen(listenfd, SOMAXCONN) == -1) {
        printf("listen error n");
        close(listenfd);
        return -1;        
    }
    /* create epoll */
    int epollfd = epoll_create(1);
    if (epollfd == -1) {
        printf("epoll_create error n");
        close(listenfd);
        return -1;           
    }
    /** struct epoll_event {
    *       uint32_t events;    fd event flags to be monitored
    *       epoll_data_t data;  User-defined data
    *   }
    *   typedef union epoll_data {
    *       void     *prt;
    *       int      fd;
    *       uint32_t u32;
    *       uint64_t u64;
    *   }
    */
    struct epoll_event listen_fd_event;
    listen_fd_event.data.fd = listenfd;
    listen_fd_event.events = EPOLLIN;  
    /**The default is LT mode, 
    *  where a fixed number of bytes are charged at once according to the
    *  service until they are collected */
    /**ET mode, when the readable event is triggered, the data on the 
    *  socket must be collected at once to feel, must be the village to 
    *  call the recv function until the recv error, the error code is EWOULDBLOCK
    */
    // listen_fd_event.events |= EPOLLET;  /* start ET */

    /* Bind the listening socket to epollfd */
    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listenfd, &listen_fd_event) == -1) {
        printf("epoll_ctl error n");
        close(listenfd);
        return -1;          
    }
    int n;
    while(1) {
        struct epoll_event epoll_events[1024];
        /* Returns the number of fd's with time */
        n = epoll_wait(epollfd, epoll_events, 1024, 1000);
        if (n < 0) {
            /* Interrupted by signal */
            if (errno == EINTR) 
                continue;
            break;
        }
        else if (n == 0) {
            /* Timeout, continue */
            continue;
        }
        for (size_t i = 0; i < n; ++ i) {
            /* Event Readable */
            if (epoll_events[i].events & EPOLLIN) {
                if (epoll_events[i].data.fd == listenfd) {
                    printf("a new client is connect! n");
                    /* Listening to sockets and receiving new connections */
                    struct sockaddr_in clientaddr;
                    socklen_t clientaddrlen = sizeof(clientaddr);
                    int clientfd = accept(listenfd, 
                                         (struct sockaddr *) &clientaddr, 
                                         &clientaddrlen);
                    if (clientfd != -1) {
                        /* Set feizuse */
                        int oldSocketFlag = fcntl(clientfd, F_GETFL, 0);
                        int newSocketFlag = oldSocketFlag | O_NONBLOCK;
                        if (fcntl(clientfd, F_SETFL, newSocketFlag) == -1) {
                            close(clientfd);
                            printf("set client to nonblocking error n");
                        }
                        else {
                            /** struct epoll_event {
                            *       uint32_t events;    fd event flags to be monitored
                            *       epoll_data_t data;  User-defined data
                            *   }
                            */
                            struct epoll_event client_fd_event;
                            client_fd_event.data.fd = clientfd;
                            /* Listening to both read and write events */
                            client_fd_event.events = EPOLLIN | EPOLLOUT;  
                            client_fd_event.events |= EPOLLET;


                            /* Add to epollfd */
                            if (epoll_ctl(epollfd, EPOLL_CTL_ADD, clientfd, &client_fd_event) != -1) {
                                // printf("new client accepted, clientfd: %d n", clientfd);       
                            }
                            else {
                                printf("add client fd to epollfd error n");
                                close(clientfd);
                            }
                        }
                    }
                }
                else {
                    printf("client fd: %d recv data n", epoll_events[i].data.fd);
                    char recvbuf[1024] = { 0 };
                    /* Receive 1 byte at a time */
                    int m = recv(epoll_events[i].data.fd, &recvbuf, 1024, 0);
                    if (m == 0) {
                        /* The other end closes the connection and removes the clienfd from the epollfd */
                        if (epoll_ctl(epollfd, EPOLL_CTL_DEL, epoll_events[i].data.fd, NULL) != -1) {
                            printf("client disconnected clientfd: %d n", epoll_events[i].data.fd);
                        }
                        close(epoll_events[i].data.fd);
                    }
                    else if (m < 0) {
                        /* error */
                        if (errno != EWOULDBLOCK && errno != EINTR) {
                            /* The other end closes the connection and removes the clienfd from the epollfd */
                            if (epoll_ctl(epollfd, EPOLL_CTL_DEL, epoll_events[i].data.fd, NULL) != -1) {
                                printf("client disconnected clientfd: %d n", epoll_events[i].data.fd);
                            }
                            close(epoll_events[i].data.fd);
                        }
                    }
                    else {
                        /* normal */
                        printf("recv from client: %d,%s", epoll_events[i].data.fd, recvbuf);
                        
                        struct epoll_event client_fd_event;
                        client_fd_event.data.fd = epoll_events[i].data.fd;
                        /* Register the writeable event to clientfd again */

                        /**In ET mode, the writable event will not be triggered all the time,
                        *  he will only trigger once and register again after the trigger is 
                        *  completed, and the writable event will continue to trigger only 
                        *  when the writable event is monitored. LT is repeatedly triggered 
                        *  by writable events. After a writable event is triggered, if it 
                        *  is no longer needed, the registration of the writable event should
                        *  be removed immediately
                        */
                        client_fd_event.events = EPOLLIN | EPOLLOUT | EPOLLET;
                        if (epoll_ctl(epollfd, EPOLL_CTL_MOD, epoll_events[i].data.fd, &client_fd_event) != -1) {
                            // printf("epoll_ctl successfully, mode: EPOLL_CTL_MOD, clientfd: %d n", epoll_events[i].data.fd);
                        }
                        else {
                            printf("epoll_ctl failure, mode: EPOLL_CTL_MOD, clientfd: %d n", epoll_events[i].data.fd);
                        }
                    }
                }
            }
            /* Listening to write events */
            else if (epoll_events[i].events & EPOLLOUT) {
                /* Handle only write events for client fd */
                if (epoll_events[i].data.fd != listenfd) {
                    /* print result */
                    // printf("EPOLLOUT Triggered, clientfd: %d n", epoll_events[i].data.fd);
                }
            }
            else if (epoll_events[i].events & EPOLLERR) {
                // TODO
                printf("epoll error! n");
            }
        }
    } 
    close(listenfd);
    return 0;
}
#endif

测试

> gcc -g -o epoll_server epoll_server.c
> ./epoll_server
a new client is connect! 
client fd: 5 recv data 
recv from client: 5,asdh
client fd: 5 recv data 
recv from client: 5,awqr
> nc -v 127.0.0.1 3119
Connection to 127.0.0.1 3119 port [tcp/*] succeeded!
asdh
awqr

最后

以上就是俭朴小松鼠为你收集整理的一个epoll的ET模式下的非阻塞的服务端小用例的全部内容,希望文章能够帮你解决一个epoll的ET模式下的非阻塞的服务端小用例所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(60)

评论列表共有 0 条评论

立即
投稿
返回
顶部