epoll

1. 背景知识

  参考 

2. Client

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <arpa/inet.h>

#define MAXLINE     80
#define SERV_PORT   8888
int main(int argc, char *argv[])
{
    struct sockaddr_in servaddr;
    char buf[MAXLINE];
    int sockfd, n;
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
    servaddr.sin_port = htons(SERV_PORT);
    connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    while (fgets(buf, MAXLINE, stdin) != NULL)
    {
        write(sockfd, buf, strlen(buf));
        n = Read(sockfd, buf, MAXLINE);
        if (n == 0)
            printf("the other side has been closed.\n");
        else
            write(STDOUT_FILENO, buf, n);
    }
    close(sockfd);
    return 0;
}
client.c

3. Server

#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#define MAXLINE            80
#define SERV_PORT        8888
#define OPEN_MAX        1024

void perr_exit(const char *s)
{
    perror(s);
    exit(1);
}

int main(int argc, char *argv[])
{
    char buf[MAXLINE]; 
    int listenfd = socket(AF_INET, SOCK_STREAM, 0);
    
    struct sockaddr_in cliaddr, servaddr;
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family      = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port        = htons(SERV_PORT);
    
    bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));

    listen(listenfd, 20);

    int efd = epoll_create(OPEN_MAX);
    if (efd == -1)
        perr_exit("epoll_create");

    struct epoll_event ev, ep[OPEN_MAX];
    ev.events  = EPOLLIN; 
    ev.data.fd = listenfd;

    int res = epoll_ctl(efd, EPOLL_CTL_ADD, listenfd, &ev);
    if (res == -1)
        perr_exit("epoll_ctl");

    while(1)
    {
        // 阻塞监听, 多路I/O复用,反应堆是一颗平衡二叉树
        int nready = epoll_wait(efd, ep, OPEN_MAX, -1); 
        if (nready == -1)
        {
            perr_exit("epoll_wait");
        }

        // 解复用,O(log2n)
        for (int i = 0; i < nready; i++)
        {
            if (! (ep[i].events & EPOLLIN))
            {
                continue;
            }

            if (ep[i].data.fd == listenfd)
            {
                socklen_t clilen = sizeof(cliaddr);
                int connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);
                char str[INET_ADDRSTRLEN];
                printf("Received msg ip: %s port: %d\n", inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)), ntohs(cliaddr.sin_port));
                ev.events  = EPOLLIN; 
                ev.data.fd = connfd;
                res = epoll_ctl(efd, EPOLL_CTL_ADD, connfd, &ev);
                if (res == -1)
                {
                    perr_exit("epoll_ctl");
                }
            }
            else
            {
                int sockfd = ep[i].data.fd;
                ssize_t n = read(sockfd, buf, MAXLINE);
                if (n == 0) 
                {
                    res = epoll_ctl(efd, EPOLL_CTL_DEL, sockfd, NULL);
                    if (res == -1)
                    {
                        perr_exit("epoll_ctl");
                    }
                    close(sockfd);
                    printf("Client %d closed\n", sockfd);
                }
                else
                {
                    for (int j = 0; j < n; j++)
                    {
                        buf[j] = toupper(buf[j]);
                    }
                    write(sockfd, buf, n);
                }
            }
        }
    }
    close(listenfd);
    close(efd);

    return 0;
}
server.c

4. 常见操作码

  参考

 

posted @ 2021-02-06 11:04  AlexOne  阅读(70)  评论(0)    收藏  举报