Linux IO多路複用

阻塞IO 每來一個請求創建一個線程

#include <stdio.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <unistd.h>
#include <pthread.h>
#include <assert.h>

#define MAX_READ_LINE 10240

static void * client_callback(void *arg) {
    int conn_fd = *(int *)arg;
    char buff[MAX_READ_LINE] = {0};

    int recv_len = recv(conn_fd, buff, MAX_READ_LINE, 0);
    assert(recv_len > 0);

    buff[recv_len] = '\0';
    fprintf(stdout, "recv message from client: %s\n", buff);

    close(conn_fd);

    return NULL;
}

int main(void) {
    struct sockaddr_in t_sockaddr;
    memset(&t_sockaddr, 0, sizeof(t_sockaddr));
    t_sockaddr.sin_family = AF_INET;
    t_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    t_sockaddr.sin_port = htons(10008);

    int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    assert(listen_fd > 0);

    int ret = bind(listen_fd, (struct sockaddr *)&t_sockaddr, sizeof(t_sockaddr));
    assert(ret != -1);

    ret = listen(listen_fd, 1024);
    assert(ret != -1);

    while(1) {
        int conn_fd = accept(listen_fd, (struct sockaddr*)NULL, NULL);
        assert(conn_fd > 0);

        pthread_t th_id;
        ret = pthread_create(&th_id, NULL, client_callback, &conn_fd);
        assert(ret == 0);
    }

    close(listen_fd);
    return 0;
}

IO多路複用-select

#include <stdio.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>

#define BUFFER_LENGTH	1024

int main(void) {
    int ret = -1;
    int server_ip_port = 10008;

    struct sockaddr_in t_sockaddr;
    memset(&t_sockaddr, 0, sizeof(t_sockaddr));
    t_sockaddr.sin_family = AF_INET;
    t_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    t_sockaddr.sin_port = htons(server_ip_port);

    int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    assert(listen_fd > 0);

    ret = bind(listen_fd,(struct sockaddr *) &t_sockaddr,sizeof(t_sockaddr));
    assert(ret != -1);

    ret = listen(listen_fd, 1024);
    assert(ret != -1);

    fd_set rfds, rset;;
    FD_ZERO(&rfds);
    FD_SET(listen_fd, &rfds);

    int max_fd = listen_fd;

    while(1) {
        rset = rfds;
        int nready = select(max_fd + 1, &rset, NULL, NULL, NULL);
        if (nready < 0) {
            continue;
        }

        if (FD_ISSET(listen_fd, &rset)) {
            struct sockaddr_in client_addr;
            memset(&client_addr, 0, sizeof(struct sockaddr_in));
            socklen_t client_len = sizeof(client_addr);
            int client_fd = accept(listen_fd, (struct sockaddr*)&client_addr, &client_len);
            if (client_fd <= 0) {
                continue;
            }

            char str[INET_ADDRSTRLEN] = {0};
            printf("recvived from %s at port %d, sockfd:%d, client_fd:%d\n", inet_ntop(AF_INET, &client_addr.sin_addr, str, sizeof(str)),
                   ntohs(client_addr.sin_port), listen_fd, client_fd);

            if (max_fd == FD_SETSIZE) {
                printf("client_fd --> out range\n");
                break;
            }
            FD_SET(client_fd, &rset);

            if (client_fd > max_fd) {
                max_fd = client_fd;
            }

            printf("sockfd:%d, max_fd:%d, client_fd:%d\n", listen_fd, max_fd, client_fd);

            if (--nready == 0) {
                continue;
            }
        }

        for (int i = listen_fd + 1;i <= max_fd; i++) {
            if (FD_ISSET(i, &rset)) {
                char buffer[BUFFER_LENGTH] = {0};
                ret = recv(i, buffer, BUFFER_LENGTH, 0);
                if (ret < 0) {
                    if (errno == EAGAIN || errno == EWOULDBLOCK) {
                        printf("read all data");
                    }
                    FD_CLR(i, &rfds);
                    close(i);
                } else if (ret == 0) {
                    printf(" disconnect %d\n", i);
                    FD_CLR(i, &rfds);
                    close(i);
                    break;
                } else {
                    printf("Recv: %s, %d Bytes\n", buffer, ret);
                }
                if (--nready == 0) {
                    break;
                }
            }
        }
    }

    close(listen_fd);

    return 0;
}

epoll模型

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/epoll.h>

#define MAX_EVENT_NUMBER 1024
#define BUFFER_SIZE 10

int setnonblocking( int fd ) {
    int old_option = fcntl( fd, F_GETFL );
    int new_option = old_option | O_NONBLOCK;
    fcntl( fd, F_SETFL, new_option );
    return old_option;
}

void addfd( int epollfd, int fd, int enable_et ) {
    struct epoll_event event;
    event.data.fd = fd;
    event.events = EPOLLIN;
    if(enable_et) {
        event.events |= EPOLLET;
    }
    epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event);
    setnonblocking(fd);
}

void lt(struct epoll_event* events, int number, int epollfd, int listenfd ) {
    char buf[ BUFFER_SIZE ];
    for (int i = 0; i < number; i++) {
        int sockfd = events[i].data.fd;
        if ( sockfd == listenfd ) {
            struct sockaddr_in client_address;
            socklen_t client_addrlength = sizeof(client_address);
            int connfd = accept(listenfd, (struct sockaddr*)&client_address, &client_addrlength);
            addfd(epollfd, connfd, -1);
        } else if (events[i].events & EPOLLIN) {
            printf( "event trigger once\n" );
            memset( buf, '\0', BUFFER_SIZE );
            int ret = recv(sockfd, buf, BUFFER_SIZE-1, 0);
            if(ret <= 0) {
                close( sockfd );
                continue;
            }
            printf("get %d bytes of content: %s\n", ret, buf);
        } else {
            printf("something else happened \n");
        }
    }
}

void et(struct epoll_event* events, int number, int epollfd, int listenfd ) {
    char buf[BUFFER_SIZE];
    for ( int i = 0; i < number; i++ ) {
        int sockfd = events[i].data.fd;
        if (sockfd == listenfd) {
            struct sockaddr_in client_address;
            socklen_t client_addrlength = sizeof(client_address);
            int connfd = accept(listenfd, (struct sockaddr*)&client_address, &client_addrlength );
            addfd(epollfd, connfd, 0);
        } else if (events[i].events & EPOLLIN) {
            printf("event trigger once\n");
            while(1) {
                memset(buf, '\0', BUFFER_SIZE);
                int ret = recv(sockfd, buf, BUFFER_SIZE-1, 0);
                if( ret < 0 ) {
                    if((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
                        printf( "read later\n" );
                        break;
                    }
                    close(sockfd);
                    break;
                } else if (ret == 0) {
                    close(sockfd);
                } else {
                    printf("get %d bytes of content: %s\n", ret, buf);
                }
            }
        } else {
            printf( "something else happened \n" );
        }
    }
}

int main(int argc, char* argv[]) {
    if(argc <= 2) {
        printf( "usage: ip_address port_number\n");
        return 1;
    }
    const char* ip = argv[1];
    int port = atoi(argv[2]);

    int ret = 0;
    struct sockaddr_in address;
    bzero(&address, sizeof(address));
    address.sin_family = AF_INET;
    inet_pton(AF_INET, ip, &address.sin_addr);
    address.sin_port = htons(port);

    int listenfd = socket(PF_INET, SOCK_STREAM, 0);
    assert(listenfd >= 0);

    ret = bind(listenfd, (struct sockaddr*)&address, sizeof(address));
    assert(ret != -1);

    ret = listen(listenfd, 5);
    assert(ret != -1);

    struct epoll_event events[MAX_EVENT_NUMBER];
    int epollfd = epoll_create(5);
    assert(epollfd != -1);
    addfd(epollfd, listenfd, 0);

    while(1) {
        int ret = epoll_wait(epollfd, events, MAX_EVENT_NUMBER, -1);
        if(ret < 0) {
            printf("epoll failure\n");
            break;
        }

        lt(events, ret, epollfd, listenfd);
        //et( events, ret, epollfd, listenfd );
    }

    close(listenfd);
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章