[C++] epoll编写的echo服务端

直接贴代码,代码是运行在Linux上面的,通过 g++ epoll.cpp编译

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

#define MAX_CONN 1024
#define BUF_SIZE 1024

int main()
{
    int serv_fd;
    char buf[BUF_SIZE];
    sockaddr_in serv_addr,cli_addr;
    int eph;
    socklen_t lt;
    struct epoll_event ev,events[MAX_CONN];
    serv_fd = socket(AF_INET,SOCK_STREAM,0);
    
    eph = epoll_create(MAX_CONN);           // 创建 epoll 句柄
    if (eph < 0)
    {
        perror("创建epoll错误");
        return -1;
    }

    // 把对监听套接字serv_fd的可读事件加入到监听列表
    ev.events = EPOLLIN|EPOLLET;
    ev.data.fd = serv_fd;
    epoll_ctl(eph,EPOLL_CTL_ADD,serv_fd,&ev);

    bzero(&serv_addr, sizeof(serv_addr));           // 类似于 memset() 清空一块内存
    inet_aton("0.0.0.0",&(serv_addr.sin_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(7007);	// 不能使用 htonl函数,执行不会 出错,但是也不会监听
    
    if(bind(serv_fd,(sockaddr*)&serv_addr,sizeof(serv_addr)) < 0)
    {
        perror("绑定错误");
        return -1;
    }
    
    listen(serv_fd,50);

    for(;;)
    {
        // 这里会阻塞,但是第三个参数指定500ms之后超时返回
        // 没有事件发生,返回0
        int n = epoll_wait(eph,events,MAX_CONN,500);       

        for(int i=0;i<n;i++)
        {
            if(events[i].data.fd == serv_fd)    // 如果是用于监听的套接字有事件发生,那就是有新连接到达了
            {
                int cli_fd = accept(serv_fd,(sockaddr*)&cli_addr,&lt);  // 接收连接
                if(cli_fd<0){perror("连接建立错误");continue;}
                printf("来自 %s 的连接\n",inet_ntoa(cli_addr.sin_addr));
                
                // 以下三行用于将新连接的套接字添加到监听列表
                ev.data.fd = cli_fd;
                ev.events = EPOLLIN | EPOLLET;      // 设置监听这个套接字的可读事件,并且指定是 ET 模式
                epoll_ctl(eph,EPOLL_CTL_ADD,cli_fd,&ev);
            }else if(events[i].events & EPOLLIN)    // 发现套接字可读
            {
                int fd = events[i].data.fd;
                int n = read(fd,buf,BUF_SIZE);
                if(n < 0)           // 接收失败,将套接字移除监听列表
                {   // 断开连接
                    ev.events = EPOLLIN;
                    ev.data.fd = fd;
                    epoll_ctl(eph,EPOLL_CTL_DEL,fd,&ev);
                    printf("断开连接\n");
                    continue;
                }
                buf[n] = '\0';
                printf("接收数据: %s\n",buf);
                
                write(fd,buf,n);    // 直接写入 发回
            }
            else if(events[i].events & EPOLLOUT)    
            {// 要注意的是,上面调用write不会触发下面这个事件, 只有满了的缓冲区重新空闲的时候会触发 https://www.zhihu.com/question/22840801
                printf("EPOLLOUT\n");
                // int fd = events[i].data.fd;
                // write(fd,buf,BUF_SIZE);
            }
        }

    }
    return 0;
}

之后客户端使用 netcat 代替
执行命令 nc 127.0.0.1 7007
就能连接上服务端,无论发什么都会发回来

posted @ 2021-02-24 20:46  Startu  阅读(208)  评论(0编辑  收藏  举报