ley*_*you 3 python sockets tcp
也许这里有人会对这件事做出回应,这只会让我疯狂.
为了简单起见,我正在做一种代理.只要它收到某些东西,它就会将所有内容转发给服务器,然后发回响应.因此,有一个套接字始终在端口4557上侦听客户端,并且对于每个传入连接,在随机端口上创建一个新套接字以连接到服务器端口4556.
客户端<==>代理<==>服务器
此外,还有另一个套接字,它被实例化并监听来自服务器的请求并转发到相应的客户端.
这是一个例子:
到目前为止,在我的测试中,我使用一个简单的python脚本向代理发送一个唯一的tcp数据包,以及一个显示接收数据并回显的转储服务器.
所以问题是当关闭与代理的连接时,也应该用"sock.close()"关闭与服务器的连接.然而它似乎完全被忽略了.套接字保持为ESTABLISHED.
现在关于代码.
几点说明.
第一个类是TCPListenerThread.它只是侦听特定端口并实例化代理(每个Client => Server couple和Server => Client couple)并转发它们的连接.
class TCPListenerThread(StoppableThread):
def __init__(self, tcp_port):
StoppableThread.__init__(self)
self.tcp_port = tcp_port
self.sock = socket.socket( socket.AF_INET, # Internet
socket.SOCK_STREAM ) # tcp
self.sock.bind( (LOCAL_ADDRESS, self.tcp_port) )
self.sock.listen(1)
def runCallback(self):
print "Listen on "+str(self.tcp_port)+".."
conn, addr = self.sock.accept()
if isFromDTN(addr):
tcpProxy = getProxyFromPort(tcp_port)
if not tcpProxy:
tcpProxy = TCPProxy(host, True)
else:
host = addr[0]
tcpProxy = getProxyFromHost(host)
if not tcpProxy:
tcpProxy = TCPProxy(host, False)
tcpProxy.handle(conn)
def finalCallback(self):
self.sock.close()
Run Code Online (Sandbox Code Playgroud)
现在出现了TCP代理:它将远程主机(客户端)与连接到服务器的端口相关联.如果它是来自新客户端的连接,它将为服务器创建一个新的侦听器(见上文),并创建一个准备好将所有内容转发到服务器的套接字.
class TCPProxy():
def __init__(self, remote, isFromDTN):
#remote = port for Server or Remote host for Client
self.isFromDTN = isFromDTN
self.conn = None
#add itself to proxy registries
#If listening from a node
if not isFromDTN:
#Set node remote host
self.remoteHost = remote
TCPProxyHostRegister[self.remoteHost] = self
#Set port to DTN interface + listener
self.portToDTN = getNewTCPPort()
TCPPortToHost[self.portToDTN] = self.remoteHost
newTCPListenerThread(self.portToDTN)
#Or from DTN
else:
self.portToDTN = remote
TCPProxyPortRegister[self.portToDTN] = self
self.remoteHost = getRemoteHostFromPortTCP(self.portToDTN)
def handle(self, conn):
print "New connection!"
#shouldn't happen, but eh
if self.conn != None:
self.closeConnections()
self.conn = conn
#init socket with remote
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
if self.isFromDTN:
self.sock.connect((self.remoteHost, 4556)) #TODO: handle dynamic port..
else:
self.sock.connect((DTN_Address, DTN_TCPPort))
#handle connection in a thread
self.handlerThread = newTCPHandlerThread(self)
#handle reply in a therad
self.replyThread = newTCPReplyThread(self)
def closeConnections(self):
try:
if self.conn != None:
print "Close connections!"
self.sock.close()
self.conn.close()
self.conn = None
self.handlerThread.kill()
self.replyThread.kill()
except Exception, err:
print str(err)
#pass
def forward(self, data):
print "TCP forwarding data: "+data
self.sock.send(data)
def forwardBack(self, data):
print "TCP forwarding data back: "+data
self.conn.send(data)
Run Code Online (Sandbox Code Playgroud)
在这个代理类中,我实例化了两个类,TCPHandlerThread和TCPReplyThread.他们分别负责转发到服务器并转发回客户端.
class TCPHandlerThread(StoppableThread):
def __init__(self, proxy):
StoppableThread.__init__(self)
self.proxy = proxy
def runCallback(self):
test = False
while 1:
data = self.proxy.conn.recv(BUFFER_SIZE)
if test:
self.proxy.sock.close()
test = True
if not data:
break
print "TCP received data:", data
self.proxy.forward(data)
self.kill()
def finalCallback(self):
self.proxy.closeConnections()
class TCPReplyThread(StoppableThread):
def __init__(self, proxy):
StoppableThread.__init__(self)
self.proxy = proxy
def runCallback(self):
while 1:
data = self.proxy.sock.recv(BUFFER_SIZE)
if not data:
break
print "TCP received back data: "+data
self.proxy.forwardBack(data)
self.kill()
def finalCallback(self):
self.proxy.closeConnections()
Run Code Online (Sandbox Code Playgroud)
您会看到,只要连接关闭,线程就会死掉,而另一个连接(客户端/服务器到代理或代理到服务器/客户端)应该在Proxy.closeConnections()中关闭
我注意到当closeConnections()是"data = self.proxy.conn.recv(BUFFER_SIZE)"时,它运行良好,但是当它在后一个语句之后被调用时,它就会出错.
我使用TCP线路,代理不发送任何"再见信号".套接字状态不会转到TIME_WAIT或其他任何东西,它只是保持ESTABLISHED.
另外,我在Windows和Ubuntu上测试过它.
这是我正在使用的三个文件,以便您可以查看整个代码.对不起,代理文件可能不太容易阅读.被支持成为一个快速的开发者.
http://hognerud.net/stackoverflow/
在此先感谢..这肯定是一些愚蠢的事情.当你看到它时,请不要太用力打我:(
小智 8
首先,我很抱歉我目前没有时间实际运行和测试您的代码.
但是我想到了这个想法,你的问题实际上可能与套接字上使用阻塞模式和非阻塞模式有关.在这种情况下,您应该检查python文档中的"socket"模块帮助,尤其是socket.setblocking().
我的猜测是,proxy.conn.recv()函数只返回,实际上是套接字收到的BUFFER_SIZE字节.因此,线程被阻塞,直到收到足够的数据,因此套接字不会被关闭.
正如我先说的那样,这只是一个猜测,所以如果不能解决问题,请不要投票给我.