UDP客户端和服务器与扭曲的Python

UDP客户端和服务器与扭曲的Python

问题描述:

我想创建一个服务器和客户端,使用Twisted从网络发送和接收UDP数据包。我已经用Python中的套接字编写了它,但是想要利用Twisted的回调和线程功能。不过,我需要帮助,但Twisted的设计。UDP客户端和服务器与扭曲的Python

我有多种类型我想收到的数据包,但是让我们假设只有一个:

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) 

我做了一个协议类(的例子几乎直接拷贝),这似乎在工作,我从另一个程序发送的数据:

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()) 

我还需要确保在客户端和服务器上设置重用地址标志,以便我可以在同一设备上同时运行多个实例(例如,一个脚本发送心跳,另一个脚本响应心跳等)。

有人可以告诉我如何用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() 

就像上面的服务器示例一样,有一个客户端示例。 这应该帮助您开始:

好吧,这里是一个使用数据报协议简单的心脏跳动发送者和接收者。

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() 
+0

我在Google的帮助下自己找到了这些示例,但它们没有解决我遇到的问题。 – Jake 2010-09-03 01:35:04

+0

@Jake这是否解决套接字重用问题或者您正在寻找其他东西? – pyfunc 2010-09-03 07:06:48

+0

+1这有效,但由于它使用多播,所以只有一个监听反应器正在接收发送者正在发送的数据。这让我更接近我所寻找的东西,这是对所有听客户的广播。 (你应该保留这个例子,以供寻找多播的人使用) – Jake 2010-09-03 15:02:18

检查出echoclient_udp.py例子。因为UDP在客户端和服务器之间几乎是对称的,所以你只需要在那里运行reactor.listenUDPconnect给服务器(它真的只是设置发送数据包的默认目的地),然后transport.write发送你的数据包。

+0

你是在暗示我打电话reactor.listenUDP两次(与服务器一次,一旦与客户端),然后调用reactor.run?我无法尝试,因为我没有设置复用地址,所以我不知道这是否真的有效。 – Jake 2010-09-03 01:32:42

+0

我建议你在每个socket上监听一次,大概是在单独的进程中,然后在每个进程中运行'reactor.run'。您需要为每个进程都有独特的(ip,port)组合。我不明白reuseaddr在什么地方进来了? – poolie 2010-09-03 01:48:59