如何处理TCP连接事件以在其他类中调用方法?
我正在创建一个机器人,它会根据通过TCP连接收到的指令来驱动。因此,我会有一个机器人类,里面有一些方法(比如sense()、drive()等),还有一个处理TCP连接的类。
为了建立TCP连接,我参考了twisted的例子。在客户端,我写了一个client.py脚本来处理连接:
from twisted.internet import reactor, protocol
import random
from eventhook import EventHook
import common
#from Common.socketdataobjects import response
# a client protocol
class EchoClient(protocol.Protocol):
"""Once connected, send a message, then print the result."""
def connectionMade(self):
self.transport.write("hello, world!")
#the server should be notified that the connection to the robot has been established
#along with robot state (position)
#eventConnectionEstablishedHook.fire()
def dataReceived(self, data):
print "Server said:", data
self.transport.write("Hello %s" % str(random.randint(1,10)))
'''
serverMessage = common.deserializeJson(data)
command = serverMessage.command
arguments = serverMessage.arguments
#here we get for example command = "DRIVE"
#arguments = {motor1Speed: 50, motor2Speed: 40}
instead of above response, used for testing purposes,
the commands should be extracted from the data and according to the command,
the method in Robot instance should be called.
When the command execution finishes, the self.transport.write() method should be called
to notify the server that the command execution finished
'''
def connectionLost(self, reason):
print "connection lost"
class EchoFactory(protocol.ClientFactory):
protocol = EchoClient
def clientConnectionFailed(self, connector, reason):
print "Connection failed - goodbye!"
reactor.stop()
def clientConnectionLost(self, connector, reason):
print "Connection lost - goodbye!"
reactor.stop()
# this connects the protocol to a server runing on port 8000
def initializeEventHandlers(connectionEstablishedHook):
global connection
connection.established = 0
global eventConnectionEstablishedHook
eventConnectionEstablishedHook = connectionEstablishedHook
def main():
f = EchoFactory()
reactor.connectTCP("localhost", 8000, f)
reactor.run()
# this only runs if the module was *not* imported
if __name__ == '__main__':
main()
除了这个脚本,我还有一个机器人类:
Class Robot(object():
def __init(self)__:
self.position = (0,0)
def drive(self, speedMotor1, speedMotor2, driveTime)
updateMotor1State(speedMotor1)
updateMotor2State(speedMotor2)
time.sleep(driveTime)
#when the execution finished, the finish status should be sent to client in order to inform the server
return "Finished"
def sense(self)
#logic to get the data from the environment
我想做的是,从TCP连接中接收数据(指令),然后在机器人实例中调用相应的方法。有些操作可能会花费更长的时间(比如驾驶),所以我尝试使用事件,但还没找到合适的方式来通过事件在TCP客户端和机器人之间进行通信:
if __name__ == '__main__':
robotController = Robot()
eventController = Controller()
connectionEstablishedHook = EventHook()
client.initializeEventHandlers(connectionEstablishedHook)
eventController.connection = connectionEstablishedHook
client.main()
我尝试创建一个ClientMainProgram脚本,想在里面创建一个机器人的实例,一个TCP客户端的实例,并实现它们之间通过事件的通信。
之前我在一个简单的例子中成功实现了事件处理,使用的是Michael Foord的事件模式。如果有人能提供这个问题的解决方案或任何类似的例子,我将非常感激,这可能会帮助我解决这个问题。
1 个回答
1
事件可以通过普通的Python函数调用来简单表示。
比如,如果你的协议看起来像这样:
from twisted.internet.protocol import Protocol
class RobotController(Protocol):
def __init__(self, robot):
self.robot = robot
def dataReceived(self, data):
for byte in data:
self.commandReceived(byte)
def commandReceived(self, command):
if command == "\x00":
# drive:
self.robot.drive()
elif command == "\x01":
# sense:
self.robot.sense()
...
(这个例子中使用的协议细节其实不是重点。我选择这个协议是因为它非常简单,几乎没有解析逻辑。对于你的实际应用,我建议你使用twisted.protocols.amp
。)
那么你只需要确保robot
这个属性被正确初始化。你可以使用一些比较新的端点API来轻松做到这一点,这些API通常可以替代工厂的使用:
from sys import argv
from twisted.internet.endpoints import clientFromString, connectProtocol
from twisted.internet.task import react
def main(reactor, description):
robot = ...
endpoint = clientFromString(reactor, description)
connecting = connectProtocol(endpoint, RobotController(robot))
def connected(controller):
...
connecting.addCallback(connected)
return connecting
react(main, argv[1:])