zoukankan      html  css  js  c++  java
  • [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 的连接
    ",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("断开连接
    ");
                        continue;
                    }
                    buf[n] = '';
                    printf("接收数据: %s
    ",buf);
                    
                    write(fd,buf,n);    // 直接写入 发回
                }
                else if(events[i].events & EPOLLOUT)    
                {// 要注意的是,上面调用write不会触发下面这个事件, 只有满了的缓冲区重新空闲的时候会触发 https://www.zhihu.com/question/22840801
                    printf("EPOLLOUT
    ");
                    // int fd = events[i].data.fd;
                    // write(fd,buf,BUF_SIZE);
                }
            }
    
        }
        return 0;
    }
    

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

  • 相关阅读:
    【权限维持】window几种隐藏技术
    Flash XSS 漏洞实例
    nginx_lua_waf 部署、测试记录
    WAF Bypass数据库特性(Access探索篇)
    WAF Bypass数据库特性(MSsql探索篇)
    WAF Bypass数据库特性(Mysql探索篇)
    WAF Bypass数据库特性(Oracle探索篇)
    WAF Bypass 笔记(SQL注入篇)
    如何关闭Struts2的webconsole.html
    Windows Server 2008 R2 WSUS服务器的详细配置和部署
  • 原文地址:https://www.cnblogs.com/cjdty/p/14443708.html
Copyright © 2011-2022 走看看