1

我正在尝试构建一个接受多个客户端连接的简单 TCP 中继。

Client1 --> TCPrelay1 --> RealServer1 --> TCPrelay1 --> Client1
Client2 --> TCPrelay1 --> RealServer1 --> TCPrelay1 --> Client2
Client3 --> TCPrelay1 --> RealServer1 --> TCPrelay1 --> Client3

在这件事上有些东西。真正的客户数量没有限制


我在这里找到了一个 UDP 中继脚本。

我试图将其修改为 TCP。我对python套接字真的很陌生。那么我的代码有什么问题呢?什么都没有发生。而且它没有中继。

#SOCK_STREAM --TCP
localPort = 5000
remotePort = 5000

#SV
remoteHost = "xxxxx"

try:
    localPort = int(localPort)
except:
    fail('Invalid port number: ' + str(localPort))
try:
    remotePort = int(remotePort)
except:
    fail('Invalid port number: ' + str(remotePort))

try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind(('', localPort))
    s.listen(1)
except:
    fail('Failed to bind on port ' + str(localPort))

knownClient = None

while True:
    conn, addr = s.accept()
    conn2, addr2 = s.connect((remoteHost, remotePort))
    data = connection.recv(1024)
    if knownClient is None:
        knownClient = addr
    if addr == knownClient:
        s.sendall(data)
        print "Sent     : " + ":".join("{0:X}".format(ord(c)) for c in data)
    else:   
        s.sendall(data)
        print "Received : " + ":".join("{0:X}".format(ord(c)) for c in data)

[忽略]
做了一些研究,在另一个 SO 问题上发现了这个逻辑:

import select

def fromAtoB(A, B):
    r, w = select.select([A], [B], [])
    if not r: select.select([A], [], [])
    elif not w: select.select([], [B], [])
    B.sendall(A.recv(4096))

但我仍在尝试了解如何实现它。

4

1 回答 1

1

您的代码接受一个连接,然后在一个方向上中继一个数据块,然后不再查看该连接。

你的第二段代码有各种各样的问题,但最大的问题是它可能会死锁。在您调用 到 期间B.sendall,如果B拒绝读取任何数据,直到它能够完成发送到A,这在您中继的协议中可能是合法的,您的代理B将永远等待对方,因为您的代理拒绝读取任何数据从B直到它完成发送。

一个适当的接力必须尝试一次做四件事,并且不能等待一件事完成后再开始另一件事。这四件事是:

1)从连接A读取。(除非已经备份了大量数据。)

2)从连接B读取。(除非已经备份了大量数据。)

3)写入连接A。(除非没有从连接B接收到未中继的数据。)

4)写入连接B。(除非没有从连接A接收到未中继的数据。)

特别是,您需要两个缓冲区,一个用于每个方向的未发送数据。您不能更改方向,因为这将要求您等待其中一个节点接收数据,如果该节点正在等待接收数据,这可能会死锁。

通常,实现代理的最简单方法是每个连接使用两个线程,每个方向一个。

于 2013-04-21T14:23:29.770 回答