我正在尝试构建一个接受多个客户端连接的简单TCP中继。
Client1 --> TCPrelay1 --> RealServer1 --> TCPrelay1 --> Client1
Client2 --> TCPrelay1 --> RealServer1 --> TCPrelay1 --> Client2
Client3 --> TCPrelay1 --> RealServer1 --> TCPrelay1 --> Client3
在那件事上。真正的客户数量没有限制
我找到了UDP中继脚本here。
我试图将其修改为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))
但是我仍在尝试了解如何实现它。
最佳答案
您的代码接受一个连接,然后在一个方向上中继一个数据块,然后不再查看该连接。
您的第二部分代码有很多问题,但是最大的问题是它可能会死锁。在调用B.sendall
的过程中,如果B
拒绝读取任何数据,直到它能够完成向A
的发送,这在您正在中继的协议(protocol)中可能是合法的,则您的代理和B
将永远互相等待,因为您的代理拒绝了从B
读取任何数据,直到完成发送。
适当的中继器必须尝试一次执行四项操作,并且不得等待另一项操作完成才开始另一项操作。这四件事是:
1)从连接A读取。(除非已经备份了大量数据。)
2)从连接B读取。(除非已经备份了大量数据。)
3)写入连接A。(除非没有从连接B接收到未中继的数据。)
4)写入连接B。(除非没有从连接A接收到未中继的数据。)
特别是,您需要两个缓冲区,一个缓冲区用于在每个方向上发送未发送的数据。您不能更改方向,因为这将需要您等待一个节点接收数据,如果该节点正在等待您接收数据,则会死锁。
通常,实现代理的最简单方法是每个连接有两个线程,每个方向一个线程。