我试图在twisted中编写一个简单的TCP服务器,它必须按顺序执行以下操作:
KEEPALIVE
标志设置为1. 以下是代码:
class MyFactory(ServerFactory):
protocol = MyProtocol
def __init__(self, service):
self.service = service
class MyProtocol(Protocol):
def connectionMade(self):
try:
self.transport.setTcpKeepAlive(1)
except AttributeError:
pass
self.deferred = Deferred()
self.deferred.addCallback(self.factory.service.compute_response)
self.deferred.addCallback(self.send_response)
def dataReceived(self, data):
self.fire(data)
def fire(self, data):
if self.deferred is not None:
d, self.deferred = self.deferred, None
d.callback(data)
def send_response(self, data):
for item in data:
d = Deferred()
d.addCallback(self.transport.write)
d.addCallback(self.wait_for_ack)
d.callback(item)
return
def wait_for_ack(self, dummy):
try:
self.transport.socket.recv(1024)
except socket.error as e:
print e
return
运行服务器和客户端后,我得到以下异常:
Resource temporarily unavailable
我理解这个异常的原因 - 我试图在非阻塞套接字上调用阻塞方法。
请帮助我找到解决此问题的方法。
答案 0 :(得分:5)
您的示例存在一些问题:
compute_response
(以及其他内容),因此我无法运行您的示例。考虑将其设为http://sscce.org send
或recv
;让Twisted为你调用这些方法。在recv
的情况下,它会将recv
的结果传递给dataReceived
。dataReceived
来接收整个信息;数据包可能always be arbitrarily fragmented in transit,因此您需要一个用于封装消息的成帧协议。然而,由于我的其他答案非常糟糕,我欠你一个关于如何设置你想做的事情的更全面的解释。
根据你的问题的规定,你的协议没有完全定义到足以给出答案;你不能用原始TCP片段做请求和响应,因为你的应用程序无法知道它们的起点和终点(见上文第3点)。所以,我发明了一个小协议来为这个例子服务:它是一个行划分的协议,客户端发送"request foo\n"
,服务器立即发送"thinking...\n"
,计算响应,然后发送{{1并等待客户端发送"response foo\n"
;作为响应,服务器将发送下一个"ok"
行或"response ..."
行,表示它已完成发送回复。
以此作为我们的协议,我相信您的问题的关键因素是您不能“等待确认”,或者就此而言,其他任何事情,在Twisted中。你需要做的是实现“当收到确认时...”时的内容。
因此,当收到消息时,我们需要确定消息的类型:确认或请求?
这是一个完整的,可运行的示例,它以这种方式实现我描述的协议:
"done\n"
我已经在标准I / O上运行了这个,所以你可以运行它并输入它以了解它是如何工作的;如果要在实际网络端口上运行它,只需用different type of endpoint替换它。希望这能回答你的问题。