我编写了TCP 中继服务器,它的工作方式类似于对等路由器(超级节点)。
最简单的情况是两个打开的套接字和它们之间的数据中继:
客户端A <---> 服务器<---> 客户端B
然而,服务器必须为大约 2000 个这样的 AB 对提供服务,即。4000个插座...
用户空间中有两个众所周知的数据流中继实现(基于socketA.recv () --> socketB.send()和socketB.recv() --> socketA.send()):
- 使用选择/轮询功能(非阻塞方法)
- 使用线程/分叉(阻塞方法)
我使用了线程,所以在最坏的情况下,服务器会创建 2*2000 个线程!我不得不限制堆栈大小并且它有效,但它是正确的解决方案吗?
我的问题的核心:
有没有办法避免用户空间中两个套接字之间的活动数据中继?
似乎有一种被动的方式。例如,我可以从每个套接字创建文件描述符,创建两个管道并使用 dup2() - 与标准输入/输出重定向相同的方法。然后两个线程对数据中继无用,可以完成/关闭。 问题是服务器是否应该关闭套接字和管道以及如何知道管道何时损坏以记录事实?
我还找到了“套接字对”,但我不确定它是否符合我的目的。
您会建议什么解决方案来卸载用户空间并限制线程数量?
一些额外的解释:
- 服务器已定义静态路由表(例如 ID_A 和 ID_B - 配对标识符)。客户端 A 连接到服务器并发送 ID_A。然后服务器等待客户端 B。当 A 和 B 配对(两个套接字都打开)时,服务器启动数据中继。
- 客户端是对称 NAT 后面的简单设备,因此 N2N 协议或 NAT 穿越技术对它们来说太复杂了。
感谢 Gerhard Rieger,我得到了提示:
我知道两种内核空间方法可以避免在用户空间中读/写、接收/发送:
- 发送文件
- 拼接
两者都有关于文件描述符类型的限制。
dup2 将无助于在内核中做某事,AFAIK。
手册页:splice(2) splice(2) vmsplice(2) sendfile(2) tee(2)
相关链接: