【发布时间】:2013-07-09 13:46:09
【问题描述】:
我编写了 TCP 中继服务器,它的工作方式类似于点对点路由器(超级节点)。
最简单的情况是两个打开的套接字和它们之间的数据中继:
clientA 服务器 clientB
但是,服务器必须为大约 2000 个这样的 A-B 对提供服务,即。 4000 个套接字...
userland 中有两个众所周知的数据流中继实现(基于 socketA.recv() --> socketB.send() 和 socketB. recv() --> socketA.send()):
- select / poll 函数的使用(非阻塞方式)
- 使用线程/分叉(阻塞方法)
我使用了线程,所以在最坏的情况下服务器会创建 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)
相关链接:
- Understanding sendfile() and splice()
- http://blog.superpat.com/2010/06/01/zero-copy-in-linux-with-sendfile-and-splice/
- http://yarchive.net/comp/linux/splice.html(莱纳斯)
- C, sendfile() and send() difference?
- bridging between two file descriptors
- Send and Receive a file in socket programming in Linux with C/C++ (GCC/G++)
- http://ogris.de/howtos/splice.html
【问题讨论】:
-
对于这么多的连接,几个线程和
epoll(4)的组合可能是你应该研究的。 -
那个,你可以使用类似libev
-
谢谢。然而,它仍然是用户态的活跃中继。我相信存在一种被动的方法。服务器以 5 秒超时等待客户端 ID,因此线程似乎是配对阶段的自然选择。
-
很好的简短比较:win.tue.nl/~aeb/linux/lk/lk-12.html。我只是在每个线程中使用了阻塞 recv() 。但是为了限制线程,我可以在一个线程中使用 epoll() 或 FASYNC。
-
其他提示:kegel.com/c10k.html