UDP-клиент и сервер с Twisted Python
Я хочу создать сервер и клиент, который отправляет и получает UDP пакеты из сети с помощью витой. Я уже написал это с помощью сокетов в Python, но хочу воспользоваться функциями обратного вызова и потоковой передачи Twisted. Тем не менее, мне нужна помощь, хотя с дизайном Twisted.
у меня есть несколько типов пакетов, которые я хочу получить, но давайте притворимся, что есть только один:
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}nn".format(self.packet_type, self.payload)
Я сделал класс протокола (почти прямую копию примеров), который кажется, работает, когда я отправляю данные из другой программы:
class MyProtocol(DatagramProtocol):
def datagramReceived(self, data, (host, port)):
p = Packet(data)
print p
reactor.listenUDP(3000, MyProtocol())
reactor.run()
чего я не знаю, так это как создать клиента, который может отправлять произвольные пакеты по сети, которые получают реактор:
# Something like this:
s = Sender()
p = Packet()
p.packet_type = 3
s.send(p.pack())
p.packet_type = 99
s.send(p.pack())
мне также нужно обязательно установить флаг адреса повторного использования на клиенте и серверах, чтобы я мог запускать несколько экземпляров каждого одновременно на одном устройстве (например, один скрипт отправляет сердцебиения, другой отвечает на сердцебиения и т. д.).
Can кто-нибудь, покажите мне, как это можно сделать с Twisted?
обновление:
вот как я это делаю с сокетами в Python. Я могу запускать несколько слушателей и отправителей одновременно, и все они слышат друг друга. Как получить этот результат с Twisted? (Прослушивание не обязательно должно быть отдельным процессом.)
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()
2 ответов
Так же, как пример сервера выше, есть пример клиента. Это должно помочь вам начать работу:
- http://www.opendocs.net/python/twisted/howto/udp.html
- http://twistedmatrix.com/documents/current/core/examples/echoclient_udp.py
Ok, вот простой отправитель и приемник сердечного ритма с использованием протокола дейтаграммы.
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()
пример трансляции просто изменяет выше подход:
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()
Проверьте echoclient_udp.py пример.
поскольку UDP в значительной степени симметричен между клиентом и сервером, вы просто хотите запустить reactor.listenUDP
там тоже connect
на сервер (который действительно просто устанавливает назначение по умолчанию для отправленных пакетов), затем transport.write
для отправки пакетов.