UDP实现高并发其实非常简单

UDP越来越被重视了,人们期望它和TCP一样,但是呢?…

UDP能不能像TCP那样做高并发?

内核早在3.9版本就支持REUSEPORT了,但直到2015年底,我也只能做个表面上(看起来像那么回事,但实际上就是垃圾的东西)的东西:
https://blog.csdn.net/dog250/article/details/17061277
但也只是看起来像,除此之外,我当时的想法相当于垃圾。

UDP做高并发非常简单,和TCP的accept模型似乎没有什么区别,下面是一个随手撸的代码,主要是跟着小小学python:

#!/usr/bin/python3
import select
import socket

sd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

sd.bind(('192.168.56.102', 1234))
sd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)

inputs = [sd]

while True:
	readable = select.select(inputs, [], [], 1.0)[0]
	for s in readable:
		if s == sd: # Accept 逻辑在此if分支实现
			data, addr = s.recvfrom(1024)
			# 创建per-客户端socket
			csd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
			csd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
			csd.bind(('192.168.56.102', 1234))
			csd.connect(addr)
			inputs.append(csd)
			print('accept connection from %s:%s' % addr, 'sd[%d] created' % csd.fileno())
		else: # 这个else分支处理per-客户端的socket
			data, addr = s.recvfrom(1024)
			if data:
				print('received "%s" from %s' % (data.splitlines()[0].decode('utf-8'), addr), 'sd[%d]' % s.fileno())
				s.sendto(data, addr)

是不是超级简单,比我之前长篇大论的垃圾强多了。

根本就一点, 只要socket数量上去了,并发也就是上去了, 因为一个socket一个读队列一个写队列,你再分身文件描述符也没鸟用,唯一的办法就是创建多个socket,这样队列操作就可以彼此分开并行处理了。至于accept逻辑,那只是让UDP看起来像TCP而已,这是次要的。

由于UDP的无连接性,在实际client发送数据前,server是不知道四元组信息的,并且也不知道UDP通信的模式,如果是oneshot,pingpong形式的数据,那谈不上什么连接跟踪的必要,但是对于类似QUIC这种 长连接 的流式数据传输而言,UDP只是承载数据的一个协议而已,这个时候只要知道了四元组,当然也就可以专门创建一个socket,用connect来保持住这个 连接 了。

问题是,当有数据进入UDP处理的时候,内核协议栈如何查找到对应的socket呢?如果socket数量数以万计,查找的开销还是可观的,这里的问题有两点:

  • 对于connected的UDP socket,无法使用REUSEPORT的四元组hash模数取余机制。
    REUSEPORT的四元组hash模数取余机制会导致同一个四元组随着socket数量增减而对应到不同的socket,无法和线程,epoll模型协同。详情看:
    https://lore.kernel.org/patchwork/patch/1129552/
  • 如果不能用REUSEPORT的模数取余机制,所有socket只能二元组hash来组织。
    所有的socket由于bind同一个地址和端口,将会位于同一个hash桶中,退化成链表。

看下效果:
在这里插入图片描述

所以说呢?这里就有优化空间了,如何用四元组来组织hash表呢?看这里:
https://blog.csdn.net/dog250/article/details/104219341

UDP在QUIC的催化作用下,近些年已经逐渐规模化了,UDP很多隐藏的实现问题逐步暴露,优化点也越来越多,事情才刚刚开始。

杏花村不让买了,也就不喝了,哎…


浙江温州皮鞋湿,下雨进水不会胖。

  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值