udp server的connect和listen

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010643777/article/details/82804321

 之前,学习tcp的时候,学习了epoll,主要应用于大连接IO事件的管理。能否将epoll和udp结合,也能管理大量的socket描述符呢?当时,查了点资料,就写了一篇博客[1]。udp是面向无连接的,在服务端,每当一个客户端数据包到来时,数据包中携带的ip和port,使得来自不同客户端的数据包是可以区分的。但是epoll是是对大量fd的管理,在新的请求到来时,就可以创建一个新的fd,用来标志一个新的连接。这个过程,[4]中有代码描述,抄在这里。

1 UDP svr创建UDP socket fd,设置socket为REUSEADDR和REUSEPORT、同时bind本地地址local_addr
listen_fd = socket(PF_INET, SOCK_DGRAM, 0)
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt,sizeof(opt))
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt))
bind(listen_fd, (struct sockaddr * ) &local_addr, sizeof(struct sockaddr))
2 创建epoll fd,并将listen_fd放到epoll中 并监听其可读事件
epoll_fd = epoll_create(1000);
ep_event.events = EPOLLIN|EPOLLET;
ep_event.data.fd = listen_fd;
epoll_ctl(epoll_fd , EPOLL_CTL_ADD, listen_fd, &ep_event)
in_fds = epoll_wait(epoll_fd, in_events, 1000, -1);
3 epoll_wait返回时,如果epoll_wait返回的事件fd是listen_fd,调用recvfrom接收client第一个UDP包并根据recvfrom返回的client地址, 创建一个新的socket(new_fd)与之对应,设置new_fd为REUSEADDR和REUSEPORT、同时bind本地地址local_addr,然后connect上recvfrom返回的client地址
recvfrom(listen_fd, buf, sizeof(buf), 0, (struct sockaddr )&client_addr, &client_len)
new_fd = socket(PF_INET, SOCK_DGRAM, 0)
setsockopt(new_fd , SOL_SOCKET, SO_REUSEADDR, &reuse,sizeof(reuse))
setsockopt(new_fd , SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse))
bind(new_fd , (struct sockaddr ) &local_addr, sizeof(struct sockaddr));
connect(new_fd , (struct sockaddr * ) &client_addr, sizeof(struct sockaddr)
4 将新创建的new_fd加入到epoll中并监听其可读等事件
client_ev.events = EPOLLIN;
client_ev.data.fd = new_fd ;
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, new_fd , &client_ev)
5 当epoll_wait返回时,如果epoll_wait返回的事件fd是new_fd 那么就可以调用recvfrom来接收特定client的UDP包了
recvfrom(new_fd , recvbuf, sizeof(recvbuf), 0, (struct sockaddr * )&client_addr, &client_len)

 这个就是epoll+udp+connect。这个想法也不是无源之水,我当时似乎看了kcp[5]的代码。时间有点久了,我已经忘了。插曲,之前加入一个udx[6]协议作者创建的群,帮主主要目的是兜售他的udx协议代码,据说优化了十多年。里面有哥们问这个udp+epoll的代码是怎么回事,我打开链接,觉得很眼熟,博客我写的。现在回想一下,我个人认为这样做并没有什么性能的提升。直接对fd进行轮询,有数据到来之后,根据协议子段或者ip:port的hash,一样可以实现epoll+udp+connect的能力,只是后者把hash查找之类的操作留给了操作系统中的处理逻辑。quic代码中server端的dispatcher使用std::map来管理session,对一个fd进行轮询,从而进行数据分发。
 另外一个就是udp+listen,这样可以多个线程监听同一个端口,充分利用cpu的处理能力。这个更有意义。例子参考quic proxy中的代码[8]。
[1]UDP下的epoll并发框架
[2]UDP的epoll并发框架-UDP Listener解决OpenVPN的并发问题
[3]使用socket so_reuseport提高服务端性能
[4]告知你不为人知的 UDP:连接性和负载均衡
[5]kcp协议
[6]UDX协议
[7]UDX与TCP BBR有什么不同
[8]stellite quic

猜你喜欢

转载自blog.csdn.net/u010643777/article/details/82804321