【问题标题】:Will Epoll work with UDP listening socket for having a event driven UDP serverEpoll 是否会与 UDP 侦听套接字一起使用以拥有事件驱动的 UDP 服务器
【发布时间】:2015-03-14 11:24:32
【问题描述】:

我正在尝试创建一个事件驱动的多线程 UDP/DTLS 服务器。设计基于以下概念

  1. 有一个客户端连接的 UDP 套接字
  2. 使用 Epoll 请求 UDP 监听套接字上的事件。
  3. UDP 套接字充当 TCP 侦听套接字并创建连接到特定客户端的子 fd。为此,我为我的对象实现了一个 UDPAccept 方法,该方法具有如下所示的伪代码

    UDPAccept(int fd,struct sockaddr * addr,
       socklen_t * addr_len,void *sockBuf,size_t *read)
    {
        //sanity checks
        int childfd = -1;
        int error = 1;
        socklen_t localLen,peerLen;
        int family;
        struct sockaddr_in         local4,peer4;
        struct sockaddr            temp;
        size_t maxLen = 65535;
        getsockname(fd,(struct sockaddr *)&temp,&localLen);
        family = temp.sa_family;
        do
        {
         childfd = socket(family,SOCK_DGRAM,0);
         //error handling       
         //handle IPV6 
         local4 = (sockaddr_in *)temp;
         error = recvfrom( fd, sockBuf,
                            maxLen,0,(struct sockaddr *)&peer4,
                                             &peerLen);
         error = bind(childfd,(struct sockaddr *)&local4,sizeof local4);
         error = connect(childfd,(struct sockaddr *)&peerV4,peerLen);
        //handle error      
       }while(0);
       if(addr != NULL && addr_len != NULL)
       {
        *addr_len = peerLen;
        addr = &peerV4;
        *read = error;
       }    
       // error handling and cleanup
       return childfd;
    }
    
  4. 将子套接字添加到 Epoll 表中。

    epoll_ctl(efd,EPOLL_CTL_ADD,newFd,&event);
    
  5. 轮询子事件并监听套接字

    currentSize = epoll_wait(efd,events,MAX_SOCKET_FD,timeout);
    //handle errors
    for(i = 0; i < currentSize;i++)
    {
    
        if(events[i].data.fd == listenUDP)
            //call UDPAccept
            // update local tables
       else
            //handle child fd events
    }
    
  6. 同一事物有多个线程,在接受期间使用锁同步

现在我的问题是 epoll 是否会停止在侦听套接字上给我 POLLIN 事件,因为我已经创建了一个新的 UDP 子连接套接字到客户端,或者我必须自己处理它

【问题讨论】:

    标签: c sockets udp dtls


    【解决方案1】:

    除非您从events 中删除第一个套接字,否则它将在两个套接字上传递事件。

    但我想知道你为什么要这样做。您可以对所有内容使用单个 UDP 套接字。这要简单得多。

    【讨论】:

    • 同意它会简单得多,但我们正在尝试构建一个迷你 DTLS 服务器,它应该可以处理 100,000 个同时以线速发送数据的客户端,我可能错了,但是使用单个套接字会结束成为瓶颈。我不确定我应该遵循什么其他设计方法。
    • 服务器将位于 40 Gbps 线路上。另一方面,我不认为网络会是一个问题,同样没有可用的基准测试只是一个假设,但是如果我们有一个单一的套接字,我们将无法处理它而不会像它那样大量丢弃数据包一次处理一个套接字的单核
    • 我相信您可以从多个线程使用相同的 UDP 套接字并获得合理的结果(尽管不确定哪个线程获取哪个传入的 UDP 数据包)。不过,我可能会按照一般原则做一个每线程的套接字。请注意,在任何一种情况下,产生差异的是多个线程的存在,而不是多个套接字的存在。
    • @cmidi 我的理解是,在大多数操作系统下,您不需要从套接字同步 recv()。 (当然,这可能只是意味着操作系统正在代表您隐式同步读取,在这种情况下,recv() 调用中可能存在相同的瓶颈;OTOH 操作系统可能正在使用一些巧妙的无锁技术来避免这种情况。并且在任何情况下,操作系统仍然必须将字节从单个网络驱动程序传递到它们的目标套接字缓冲区,所以在我看来,除非操作系统实现者已经无锁,否则无论如何都会有一个同步步骤)跨度>
    • @EJP 你是绝对正确的,拥有 UDP 接受的整个设计是基于创建基于套接字 fd 的 DTLS SSL object 关联,因为 SSL_read SSL_write 在同一个套接字上的调用不是线程安全。根据您的建议,我实际上能够设计一个状态机,其中我的 UDP 侦听套接字通过向它们的表中添加子套接字来为我的多个 epoll 线程创建工作。我必须有专用的 UDP 侦听套接字线程,因为正如您在回答中所建议的那样,我也在侦听套接字上为所有子套接字数据获取 epoll 事件。
    【解决方案2】:

    根据关于 connect() 的 Linux 手册页,过滤器将确保只有来自“已连接”对等方的数据报才会传送到新套接字。

    但有一点需要注意... bind() 调用将暂时接管侦听器的端口,直到 connect 调用()。这是一个小窗口,但可能导致来自其他客户端的数据报出现在“已连接”套接字上。您可以通过验证对等地址来忽略它们。

    【讨论】:

      猜你喜欢
      • 2017-09-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-15
      • 2016-01-03
      • 2012-09-06
      • 2015-11-28
      相关资源
      最近更新 更多