Epoll 将与 UDP 侦听套接字一起使用以拥有事件驱动的 UDP 服务器
Will Epoll work with UDP listening socket for having a event driven UDP server
我正在尝试创建一个事件驱动的多线程 UDP/DTLS 服务器。该设计基于以下概念
- 有客户端连接的 UDP 套接字
- 使用 Epoll 请求 UDP 侦听套接字上的事件。
UDP套接字充当TCP侦听套接字并创建连接到特定客户端的子fds。为此,我为我的对象实现了一个 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;
}
将子套接字添加到 Epoll table.
epoll_ctl(efd,EPOLL_CTL_ADD,newFd,&event);
轮询子节点上的事件并监听套接字
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
}
有多个线程处理同一事物,在接受期间使用锁进行同步
现在我的问题是 epoll 是否会停止在侦听套接字上给我 POLLIN 事件,因为我已经创建了一个新的 UDP 子连接套接字到客户端,或者我必须自己处理它
它将在两个套接字上传递事件,除非您从 events
中删除第一个套接字。
但我想知道你为什么要这样做。您可以对所有内容使用单个 UDP 套接字。简单多了。
根据 connect() 的 Linux 手册页,过滤器将确保只有来自 "connected" 对等方的数据报才会被传送到新套接字。
但有一个警告...bind() 调用将短暂地从侦听器接管端口,直到连接调用()。它很小 window,但会导致来自其他客户端的数据报出现在 "connected" 套接字上。您可以通过验证对等地址来忽略它们。
我正在尝试创建一个事件驱动的多线程 UDP/DTLS 服务器。该设计基于以下概念
- 有客户端连接的 UDP 套接字
- 使用 Epoll 请求 UDP 侦听套接字上的事件。
UDP套接字充当TCP侦听套接字并创建连接到特定客户端的子fds。为此,我为我的对象实现了一个 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; }
将子套接字添加到 Epoll table.
epoll_ctl(efd,EPOLL_CTL_ADD,newFd,&event);
轮询子节点上的事件并监听套接字
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 }
有多个线程处理同一事物,在接受期间使用锁进行同步
现在我的问题是 epoll 是否会停止在侦听套接字上给我 POLLIN 事件,因为我已经创建了一个新的 UDP 子连接套接字到客户端,或者我必须自己处理它
它将在两个套接字上传递事件,除非您从 events
中删除第一个套接字。
但我想知道你为什么要这样做。您可以对所有内容使用单个 UDP 套接字。简单多了。
根据 connect() 的 Linux 手册页,过滤器将确保只有来自 "connected" 对等方的数据报才会被传送到新套接字。
但有一个警告...bind() 调用将短暂地从侦听器接管端口,直到连接调用()。它很小 window,但会导致来自其他客户端的数据报出现在 "connected" 套接字上。您可以通过验证对等地址来忽略它们。