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

世上唯一不能复制的是时间,唯一不能重演的是人生,唯一不劳而获的是年龄。该怎么走,过什么样的生活,全凭自己的选择和努力。人生很贵,请别浪费!与智者为伍,与良善者同行。[C++] epoll编写的echo服务端,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

直接贴代码,代码是运行在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
就能连接上服务端,无论发什么都会发回来

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/225565.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!