使用 Twisted Python 的 UDP 客户端和服务器 [英] UDP client and server with Twisted Python
问题描述
我想创建一个服务器和客户端,使用 Twisted 从网络发送和接收 UDP 数据包.我已经用 Python 中的套接字编写了这个,但想利用 Twisted 的回调和线程功能.但是,我需要有关 Twisted 设计的帮助.
I want to create a server and client that sends and receives UDP packets from the network using Twisted. I've already written this with sockets in Python, but want to take advantage of Twisted's callback and threading features. However, I need help though with the design of Twisted.
我想接收多种类型的数据包,但让我们假设只有一种:
I have multiple types of packets I want to receive, but let's pretend there is just one:
class Packet(object):
def __init__(self, data=None):
self.packet_type = 1
self.payload = ''
self.structure = '!H6s'
if data == None:
return
self.packet_type, self.payload = struct.unpack(self.structure, data)
def pack(self):
return struct.pack(self.structure, self.packet_type, self.payload)
def __str__(self):
return "Type: {0}\nPayload {1}\n\n".format(self.packet_type, self.payload)
我制作了一个协议类(几乎是示例的直接副本),当我从另一个程序发送数据时,它似乎可以工作:
I made a protocol class (almost direct copy of the examples), which seems to work when I send data from another program:
class MyProtocol(DatagramProtocol):
def datagramReceived(self, data, (host, port)):
p = Packet(data)
print p
reactor.listenUDP(3000, MyProtocol())
reactor.run()
我不知道如何创建一个可以在网络上发送任意数据包的客户端,这些数据包会被反应器接收:
What I don't know is how do I create a client which can send arbitrary packets on the network, which get picked up by the reactor:
# Something like this:
s = Sender()
p = Packet()
p.packet_type = 3
s.send(p.pack())
p.packet_type = 99
s.send(p.pack())
我还需要确保在客户端和服务器上设置重用地址标志,以便我可以在同一设备上同时运行每个实例的多个实例(例如,一个脚本正在发送心跳,另一个脚本响应心跳等).
I also need to make sure to set the reuse address flag on the client and servers so I can run multiple instances of each at the same time on the same device (e.g. one script is sending heartbeats, another responds to heartbeats, etc).
有人可以告诉我如何使用 Twisted 做到这一点吗?
Can someone show me how this could be done with Twisted?
更新:
这就是我在 Python 中使用套接字的方式.我可以同时运行多个侦听器和发送器,并且他们都能听到对方的声音.如何使用 Twisted 获得此结果?(聆听部分不需要是一个单独的过程.)
This is how I do it with sockets in Python. I can run multiple listeners and senders at the same time and they all hear each other. How do I get this result with Twisted? (The listening portion need not be a separate process.)
class Listener(Process):
def __init__(self, ip='127.0.0.1', port=3000):
Process.__init__(self)
self.ip = ip
self.port = port
def run(self):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((self.ip, self.port))
data, from_ip = sock.recvfrom(4096)
p = Packet(data)
print p
class Sender(object):
def __init__(self, ip='127.255.255.255', port=3000):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.ip = (ip, port)
def send(self, data):
self.sock.sendto(data, self.ip)
if __name__ == "__main__":
l = Listener()
l.start()
s = Sender()
p = Packet()
p.packet_type = 4
p.payload = 'jake'
s.send(p.pack())
可行的解决方案:
class MySender(DatagramProtocol):
def __init__(self, packet, host='127.255.255.255', port=3000):
self.packet = packet.pack()
self.host = host
self.port = port
def startProtocol(self):
self.transport.write(self.packet, (self.host, self.port))
if __name__ == "__main__":
packet = Packet()
packet.packet_type = 1
packet.payload = 'jake'
s = MySender(packet)
reactor.listenMulticast(3000, MyProtocol(), listenMultiple=True)
reactor.listenMulticast(3000, s, listenMultiple=True)
reactor.callLater(4, reactor.stop)
reactor.run()
推荐答案
就像上面的服务器示例一样,有一个客户端示例.这应该可以帮助您入门:
Just like the server example above, there is a client example to. This should help you get started:
- https://twistedmatrix.com/documents/current/core/howto/udp.html
- https://github.com/twisted/twisted/blob/trunk/docs/core/examples/echoclient_udp.py
好的,这是一个使用数据报协议的简单心跳发送器和接收器.
Ok, here is a simple heart beat sender and receiver using datagram protocol.
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
from twisted.internet.task import LoopingCall
import sys, time
class HeartbeatSender(DatagramProtocol):
def __init__(self, name, host, port):
self.name = name
self.loopObj = None
self.host = host
self.port = port
def startProtocol(self):
# Called when transport is connected
# I am ready to send heart beats
self.loopObj = LoopingCall(self.sendHeartBeat)
self.loopObj.start(2, now=False)
def stopProtocol(self):
"Called after all transport is teared down"
pass
def datagramReceived(self, data, (host, port)):
print "received %r from %s:%d" % (data, host, port)
def sendHeartBeat(self):
self.transport.write(self.name, (self.host, self.port))
class HeartbeatReciever(DatagramProtocol):
def __init__(self):
pass
def startProtocol(self):
"Called when transport is connected"
pass
def stopProtocol(self):
"Called after all transport is teared down"
def datagramReceived(self, data, (host, port)):
now = time.localtime(time.time())
timeStr = str(time.strftime("%y/%m/%d %H:%M:%S",now))
print "received %r from %s:%d at %s" % (data, host, port, timeStr)
heartBeatSenderObj = HeartbeatSender("sender", "127.0.0.1", 8005)
reactor.listenMulticast(8005, HeartbeatReciever(), listenMultiple=True)
reactor.listenMulticast(8005, heartBeatSenderObj, listenMultiple=True)
reactor.run()
广播示例只是修改了上面的方法:
The broadcast example simply modifies the above approach:
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
from twisted.internet.task import LoopingCall
import sys, time
class HeartbeatSender(DatagramProtocol):
def __init__(self, name, host, port):
self.name = name
self.loopObj = None
self.host = host
self.port = port
def startProtocol(self):
# Called when transport is connected
# I am ready to send heart beats
self.transport.joinGroup('224.0.0.1')
self.loopObj = LoopingCall(self.sendHeartBeat)
self.loopObj.start(2, now=False)
def stopProtocol(self):
"Called after all transport is teared down"
pass
def datagramReceived(self, data, (host, port)):
print "received %r from %s:%d" % (data, host, port)
def sendHeartBeat(self):
self.transport.write(self.name, (self.host, self.port))
class HeartbeatReciever(DatagramProtocol):
def __init__(self, name):
self.name = name
def startProtocol(self):
"Called when transport is connected"
self.transport.joinGroup('224.0.0.1')
pass
def stopProtocol(self):
"Called after all transport is teared down"
def datagramReceived(self, data, (host, port)):
now = time.localtime(time.time())
timeStr = str(time.strftime("%y/%m/%d %H:%M:%S",now))
print "%s received %r from %s:%d at %s" % (self.name, data, host, port, timeStr)
heartBeatSenderObj = HeartbeatSender("sender", "224.0.0.1", 8005)
reactor.listenMulticast(8005, HeartbeatReciever("listner1"), listenMultiple=True)
reactor.listenMulticast(8005, HeartbeatReciever("listner2"), listenMultiple=True)
reactor.listenMulticast(8005, heartBeatSenderObj, listenMultiple=True)
reactor.run()
这篇关于使用 Twisted Python 的 UDP 客户端和服务器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!