gpt4 book ai didi

Python:SocketServer 意外关闭 TCP 连接

转载 作者:可可西里 更新时间:2023-11-01 02:33:05 29 4
gpt4 key购买 nike

我想实现一个向 Python 发送请求的 TCP/IP 网络客户端应用程序 SocketServer并期望得到回应。我已经开始使用官方 Python SocketServer sample code :

server.py:

#!/usr/bin/env python
# encoding: utf-8

import SocketServer

class MyTCPHandler(SocketServer.StreamRequestHandler):

def handle(self):
request = self.rfile.readline().strip()
print "RX [%s]: %s" % (self.client_address[0], request)

response = self.processRequest(request)

print "TX [%s]: %s" % (self.client_address[0], response)
self.wfile.write(response)

def processRequest(self, message):
if message == 'request type 01':
return 'response type 01'
elif message == 'request type 02':
return 'response type 02'

if __name__ == "__main__":
server = SocketServer.TCPServer(('localhost', 12345), MyTCPHandler)
server.serve_forever()

client.py:

#!/usr/bin/env python
# encoding: utf-8

import socket

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

try:
sock.connect(('127.0.0.1', 12345))

data = 'request type 01'
sent = sock.sendall(data + '\n')
if sent == 0:
raise RuntimeError("socket connection broken")

received = sock.recv(1024)
print "Sent: {}".format(data)
print "Received: {}".format(received)

data = 'request type 02'
sent = sock.sendall(data + '\n')
if sent == 0:
raise RuntimeError("socket connection broken")

received = sock.recv(1024)
print "Sent: {}".format(data)
print "Received: {}".format(received)

except Exception as e:
print e

finally:
sock.close()

server.py 输出:

RX [127.0.0.1]: request type 01
TX [127.0.0.1]: response type 01

client.py 输出:

Sent:     request type 01
Received: response type 01
[Errno 54] Connection reset by peer

哪里做错了?似乎服务器正在关闭连接。我怎样才能让它保持打开状态?

注意:这是 C++/Qt: QTcpSocket won't write after reading 的后续问题

更新(在 abarnert's answer 之后):

我从中得到的是 SocketServer.StreamRequestHandler 不是最新的设计,虽然它允许我通过网络连接,但它并不真正支持我使用所有 TCP/我需要注意 IP 相关方面以实现稳健的通信。

这已在 Python 3 中通过 asyncio 得到解决。 ,但由于该项目存在于 Python 2 中,所以这不是一个选项。因此,我在 Twisted 中实现了上面描述的服务器和客户端。 :

server.py:

#!/usr/bin/env python
# encoding: utf-8

from twisted.internet.protocol import Factory
from twisted.protocols.basic import LineReceiver
from twisted.internet import reactor

class SimpleProtocol(LineReceiver):

def connectionMade(self):
print 'connectionMade'

# NOTE: lineReceived(...) doesn't seem to get called

def dataReceived(self, data):
print 'dataReceived'
print 'RX: %s' % data

if data == 'request type 01':
response = 'response type 01'
elif data == 'request type 02':
response = 'response type 02'
else:
response = 'unsupported request'

print 'TX: %s' % response
self.sendLine(response)

class SimpleProtocolFactory(Factory):

def buildProtocol(self, addr):
return SimpleProtocol()

reactor.listenTCP(12345, SimpleProtocolFactory(), interface='127.0.0.1')
reactor.run()

client.py:

#!/usr/bin/env python
# encoding: utf-8

from twisted.internet import reactor
from twisted.internet.protocol import Protocol
from twisted.internet.endpoints import TCP4ClientEndpoint, connectProtocol

class SimpleClientProtocol(Protocol):
def sendMessage(self, msg):
print "[TX]: %s" % msg
self.transport.write(msg)

def gotProtocol(p):
p.sendMessage('request type 01')
reactor.callLater(1, p.sendMessage, 'request type 02')
reactor.callLater(2, p.transport.loseConnection)

point = TCP4ClientEndpoint(reactor, '127.0.0.1', 12345)
d = connectProtocol(point, SimpleClientProtocol())
d.addCallback(gotProtocol)
reactor.run()

客户端不会关闭,而是空闲直到CTRL+C。 Twisted 可能需要一段时间才能让我理解,但对于手头的工作来说,使用经过测试和试用的框架显然比自己完成所有这些基础工作更合理。

注意:这在 Twisted XmlStream: How to connect to events? 处继续

最佳答案

这里的问题是,在 TCPHandler 中,“请求”实际上是一个完整的连接,从开始到结束。* 您的处理程序在 accept 时被调用,并且当您从它返回时,套接字将关闭。

如果你想在此基础上构建一个请求-响应-协议(protocol)处理程序,它在单个套接字级请求上处理多个协议(protocol)级请求,你必须自己做(或使用更高级别的框架) . (像 BaseHTTPServer 这样的子类演示了如何做到这一点。)

例如,您可以在handle 函数中使用一个循环。当然你可能想在这里添加一个异常处理程序和/或处理来自 rfile 的 EOF(注意 self.rfile.readline() 将返回 '' 用于 EOF,但 '\n' 用于空行,因此您必须在调用 strip 之前检查它,除非您希望空行表示“退出”在你的协议(protocol)中)。例如:

def handle(self):
try:
while True:
request = self.rfile.readline()
if not request:
break
request = request.rstrip()
print "RX [%s]: %s" % (self.client_address[0], request)

response = self.processRequest(request)

print "TX [%s]: %s" % (self.client_address[0], response)
self.wfile.write(response + '\n')
except Exception as e:
print "ER [%s]: %r" % (self.client_address[0], e)
print "DC [%s]: disconnected" % (self.client_address[0])

这将经常与您现有的客户端一起工作,至少在卸载机器上的本地主机上,但它实际上并不正确,而且“经常工作”很少足够好。参见 TCP sockets are byte streams, not message streams对于更长时间的讨论,但简而言之,您需要做 David Schwarz's answer 中提到的事情:将换行符附加到您从服务器写入的内容(我已经在上面做了),并让客户端逐行读取,而不是一次只尝试读取 1024 个字节(您可以通过编写自己的缓冲区和-分割线代码,或仅通过使用 makefile 方法,因此它可以像服务器端一样使用 rfile.readline()。)

不修复客户端不会导致回答 claim 的问题,但它导致这样的问题:

Sent:     request type 01
Received: resp
Sent: request type 02
Received: onse type 01
response typ

并且您可以看到,在实际尝试以编程方式处理响应的真实程序中,像 response type 01\nresponse typ 这样的响应不会发生非常有用……


* 请注意,SocketServer 是一种没有人真正喜爱的古老设计。 Python 3 添加 asyncio 是有原因的,Python 2 中的人们通常使用第三方框架,如 Twistedgevent .它们对于简单任务来说更简单,对于复杂任务来说更灵活/强大(并且效率更高)。

关于Python:SocketServer 意外关闭 TCP 连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29571770/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com