两个TCP套接字之间的基于内核(Linux)的数据中继

时间:2013-07-11 10:17:57

标签: sockets tcp kernel splice

我写了 TCP中继服务器,它的作用类似于点对点路由器(超级节点)。

最简单的情况是两个打开的套接字和它们之间的数据中继:

clientA< --->服务器< ---> clientB

然而,服务器必须服务大约2000个这样的A-B对,即。 4000个插座...

userland 中有两个众所周知的数据流中继实现(基于 socketA.recv() - > socketB.send() socketB .recv() - > socketA.send()):

  • 使用选择 / 民意调查函数(非阻塞方法)
  • 使用线程/分叉(阻塞方法)

我使用线程,所以在最坏的情况下,服务器创建2 * 2000个线程!我不得不限制堆栈大小并且它可以工作但是它是正确的解决方案吗?

我的问题的核心:

有没有办法避免用户空间中两个套接字之间的活动数据中继?

似乎有一种被动的方式。例如,我可以从每个套接字创建文件描述符,创建两个管道并使用dup2() - 与stdin / out重定向相同的方法。然后两个线程对数据中继没用,可以完成/关闭。 问题是服务器是否应该关闭套接字和管道以及如何知道管道何时损坏以记录事实?

我还发现了"套接字对"但为了我的目的,我不确定。

您建议哪些解决方案可以卸载用户空间并限制线程数量?

一些额外的解释:

  • 服务器已定义静态路由表(例如ID_A与ID_B - 配对标识符)。客户端A连接到服务器并发送ID_A。然后服务器等待客户端B.当A和B配对(两个套接字都打开)时,服务器启动数据中继。
  • 客户端是对称NAT背后的简单设备,因此N2N协议或NAT遍历技术对它们来说过于复杂。

感谢Gerhard Rieger,我有提示:

  

我知道有两种内核空间方式可以避免读/写,recv / send   用户空间:

     
      
  • 的sendfile
  •   
  • 剪接
  •   
     

两者都有关于文件描述符类型的限制。

     

dup2无助于在内核中执行某些操作,AFAIK。

手册页:splice(2) splice(2) vmsplice(2) sendfile(2) tee(2)

相关链接:

2 个答案:

答案 0 :(得分:6)

OpenBSD实现了SO_SPLICE:

Linux是否支持类似的东西或只有自己的内核模块才是解决方案?

答案 1 :(得分:3)

即使对于2000个并发连接的负载,我也绝不会使用线程。它们具有最高的堆栈和交换开销,因为确保在任何地方都可以中断,而不是只能在特定位置中断时,它总是更加昂贵。只需使用epoll()和splice(如果您的套接字是TCP,这似乎是这种情况),你会没事的。你甚至可以在事件触发模式下使epoll工作,你只需要注册你的fds一次。

如果你绝对想要使用线程,每个CPU核心使用一个线程来分散负载,但是如果你需要这样做,那就意味着你正在以亲和力,每个CPU插槽上的RAM位置等速度进行游戏。扮演重要角色,在你的问题中似乎并非如此。所以我假设单个线程在你的情况下绰绰有余。