场景非常简单:
使用 TCP/IP 我有一个连接到我的客户端(服务器)我想将套接字发送给我的数据转发到我打开的另一个套接字,并将我从该套接字接收的数据向后转发。就像代理一样。
现在我有 1 个线程,它从传入连接中侦听,并在建立来自客户端的连接时产生另外 2 个线程。我必须使用一种机制在线程中进行通信。
有什么更简单的东西可以用作 TCP/IP 代理吗?Linux 是否有套接字转发或某种机制?
您可以使用 iptables 进行端口转发。这不是交流解决方案,但它是具有良好性能且调试最少的2 行代码。
从第二个链接:
iptables -A PREROUTING -t nat -i eth1 -p tcp \
--dport 80 -j DNAT --to 192.168.1.50:80
iptables -A INPUT -p tcp -m state --state NEW \
--dport 80 -i eth1 -j ACCEPT
第一行从端口 80 转发到 192.168.1.50 上的端口 80,第二行接受连接,防止 iptables 丢弃它。
您可以使用其他 iptables 标志添加额外的约束,例如-s 10.0.3.0/24
将捕获源为 10.0.3.0 到 10.0.3.255 的所有地址
一种用户级解决方案是使用socat
. 例如,要接受端口 8080 上的连接并将它们转发到 192.168.1.50:9090,您可以使用:
socat TCP-LISTEN:8080,fork TCP:192.168.1.50:9090
该fork
选项socat
允许多个连接。
你不需要线程。看看select()
,epoll()
或者kqueue()
为了在没有任何线程的情况下管理多个套接字(如果你在 Windows 上,它就是completion port
)。
这是一个基于选择的服务器的例子,这将是一个好的开始。
对于简单的套接字转发,让内核来做。使用 iptables 或其中一个前端来配置它。
如果您需要复杂的数据嗅探/修改/转发以供实际使用,请编写一个 iptables 模块。
如果您需要 tee(复制/拆分)数据流,或者检查或修改数据,请继续阅读。
Linux 2.6.17 及更高版本以及 glibc 2.5 及更高版本确实提供了一些不错的功能:splice()
和tee()
. 您可以使用这些来避免将有效负载复制到用户空间或从用户空间复制,告诉内核将特定数量的字节从一个描述符传输到另一个描述符。(tee()
不消耗数据,允许您将数据的一个或多个副本发送到其他描述符。)
您可以在每个连接中使用两个线程(每个方向一个),并根据需要让每个线程读取检查/损坏/发球数据流。当您知道有N个传入字节要转发到一个传出套接字时,请使用splice()
. 如果您有多个传出套接字,请使用非阻塞传出套接字,tee()
一次使用小块(但splice()
用于每个块的最后一个传出套接字)。
您的线程可以读取部分/全部传入数据以决定如何处理它,但请记住,在使用or之前,您需要发送write()
或send()
您已经读取的部分需要发送;他们不会神奇地获取已经消耗的数据。splice()
tee()