twisted 中udp使用(twisted附带文档)

UDP Networking

1.      Overview

2.      DatagramProtocol

3.      Connected UDP

4.      Multicast UDP

5.      Acknowledgements

UDP

1.            概述

2.            数据包协议

3.            连接UDP

4.            组播UDP

5.            致谢

 

概述

不像TCPUDP没有连接的概念。一个UDP socket可以从网络上任何服务器接收数据包,也可以将数据包发送到网络上的任何主机。而且数据包在传输中可以以任意顺序到达,不全部到达,或者被复制。

既然这里没有多重连接,对所有UDPsocket我们只需要使用一个单独的对象,一个协议。然后使用反应器将这个协议连接到UDP端口,基于twisted.internet.interfaces.IReactorUDP反应器API

Overview

Unlike TCP, UDP has no notion of connections. A UDP socket can receive datagrams from any server on the network, and send datagrams to any host on the network. In addition, datagrams may arrive in any order, never arrive at all, or be duplicated in transit.

Since there are no multiple connections, we only use a single object, a protocol, for each UDP socket. We then use the reactor to connect this protocol to a UDP transport, using the twisted.internet.interfaces.IReactorUDP reactor API.

数据包协议

       真实实现协议解析和处理的地方是DatagramProtocol类。它通常继承twisted.internet.protocol.DatagramProtocol。大部分协议处理也从这个类和它的子类继承。DatagramProtocol类接收数据包,通过网络发送它们。接收到的数据包包含他们是从哪里被发送的地址,当发送数据包时必须指定地址。

这是一个简单的例子:

DatagramProtocol

At the base, the place where you actually implement the protocol parsing and handling, is the DatagramProtocol class. This class will usually be decended from twisted.internet.protocol.DatagramProtocol. Most protocol handlers inherit either from this class or from one of its convenience children. The DatagramProtocol class receives datagrams, and can send them out over the network. Received datagrams include the address they were sent from, and when sending datagrams the address to send to must be specified.

Here is a simple example:

from twisted.internet.protocol import DatagramProtocol

from twisted.internet import reactor

 

class Echo(DatagramProtocol):

   

    def datagramReceived(self, data, (host, port)):

        print "received %r from %s:%d" % (data, host, port)

        self.transport.write(data, (host, port))

 

reactor.listenUDP(9999, Echo())

reactor.run()

如你所看到的,协议在反应器上注册。这意味着在它被添加到一个应用时将保持不变,因此它在从一个UDP socket连接和断开时twisted.internet.protocol.DatagramProtocol.startProtocol twisted.internet.protocol.DatagramProtocol.stopProtocol方法将被调用。

协议的transport属性实现twisted.internet.interfaces.IUDPTransport接口。注意host参数影视一个IP,而不是主机名。如果只有主机名使用reactor.resolve()解析地址(twisted.internet.interfaces.IReactorCore.resolve

As you can see, the protocol is registed with the reactor. This means it may be persisted if it's added to an application, and thus it has twisted.internet.protocol.DatagramProtocol.startProtocol and twisted.internet.protocol.DatagramProtocol.stopProtocol methods that will get called when the protocol is connected and disconnected from a UDP socket.

The protocol's transport attribute will implement the twisted.internet.interfaces.IUDPTransport interface. Notice that the host argument should be an IP, not a hostname. If you only have the hostname use reactor.resolve() to resolve the address (see twisted.internet.interfaces.IReactorCore.resolve).

已连接的UDP

一个已连接的UDP socket非常不同于标准的socket,它只和一个地址接收和发送数据包,但是这并不是一个可靠的连接。数据包可能以任意顺序到达,对端的端口也可能没有在监听。已连接的UDP的好处是可以提供通知和非指定的包。这依赖于很多因素,基本上这些因素都在应用可控范围之外,但是这仍然提供了在有时很有用的特定好处。

不像标准的UDP协议,我们不需要指定将数据包向何处发送和告知它们从何处而来,因此他们只能来自于socket“连接”上的地址。

Connected UDP

A connected UDP socket is slighly different from a standard one - it can only send and receive datagrams to/from a single address, but this does not in any way imply a connection. Datagrams may still arrive in any order, and the port on the other side may have no one listening. The benefit of the connected UDP socket is that it it may provide notification of undelivered packages. This depends on many factors, almost all of which are out of the control of the application, but it still presents certain benefits which occassionally make it useful.

Unlike a regular UDP protocol, we do not need to specify where to send datagrams to, and are not told where they came from since they can only come from address the socket is 'connected' to.

from twisted.internet.protocol import DatagramProtocol

from twisted.internet import reactor

 

class Helloer(DatagramProtocol):

 

    def startProtocol(self):

        self.transport.connect("192.168.1.1", 1234)

        print "we can only send to %s now" % str((host, port))

        self.transport.write("hello") # no need for address

       

    def datagramReceived(self, data, (host, port)):

        print "received %r from %s:%d" % (data, host, port)

 

    # Possibly invoked if there is no server listening on the

    # address to which we are sending.

    def connectionRefused(self):

        print "No one listening"

 

# 0 means any port, we don't care in this case

reactor.listenUDP(0, Helloer())

reactor.run()

注意:connect() write()一样都只接收IP地址,不接受未解析的域名。要得到域的IP使用reactor.resolve(),如下:

Note that connect(), like write() will only accept IP addresses, not unresolved domain names. To obtain the IP of a domain name use reactor.resolve(), e.g.:

from twisted.internet import reactor

 

def gotIP(ip):

    print "IP of 'example.com' is", ip

 

reactor.resolve('example.com').addCallback(gotIP)

在前一个连接完成后连接一个新的地址,或者使现已连接的端口断开现在还不支持,可能在将来加入。

Connecting to a new address after a previous connection, or making a connected port unconnected are not currently supported, but will likely be supported in the future.

组播DUP

一个组播UDPsocket可以从多个客户端发送和接收数据包。组播有趣和有用的特性在于客户端在不知道任何主机的特定IP可以用一个包联系多个服务器。

 

Multicast UDP

A multicast UDP socket can send and receive datagrams from multiple clients. The interesting and useful feature of the multicast is that a client can contact multiple servers with a single packet, without knowing the specific IP of any of the hosts.

from twisted.internet.protocol import DatagramProtocol

from twisted.internet import reactor

from twisted.application.internet import MulticastServer

 

class MulticastServerUDP(DatagramProtocol):

    def startProtocol(self):

        print 'Started Listening'

        # Join a specific multicast group, which is the IP we will respond to

        self.transport.joinGroup('224.0.0.1')

 

    def datagramReceived(self, datagram, address):

        # The uniqueID check is to ensure we only service requests from

        # ourselves

        if datagram == 'UniqueID':

            print "Server Received:" + repr(datagram)

            self.transport.write("data", address)

 

# Note that the join function is picky about having a unique object

# on which to call join.  To avoid using startProtocol, the following is

# sufficient:

#reactor.listenMulticast(8005, MulticastServerUDP()).join('224.0.0.1')

 

# Listen for multicast on 224.0.0.1:8005

reactor.listenMulticast(8005, MulticastServerUDP())

reactor.run()

Source listing - listings/udp/MulticastServer.py

服务器协议很简单,类似于一个listenUDP实现。主要的区别在于不同于listenUDPlistenMulticast使用一个特定的端口号被呼叫。服务器使用joinGroup来指定服务需要那个组播IP地址。另一个不同的地方在于数据包的内容。很多不同的应用使用组播来进行设备发现,导致包流动过多。检查有效载荷可以保证我们只服务我们指定的客户端的要求。

The server protocol is very simple, and closely resembles a normal listenUDP implementation. The main difference is that instead of listenUDP, listenMulticast is called with a specified port number. The server must also call joinGroup to specify on which multicast IP address it will service requests. Another item of interest is the contents of the datagram. Many different applications use multicast as a way of device discovery, which leads to an abundance of packets flying around. Checking the payload can ensure that we only service requests from our specific clients.

from twisted.internet.protocol import DatagramProtocol

from twisted.internet import reactor

from twisted.application.internet import MulticastServer

 

class MulticastClientUDP(DatagramProtocol):

 

    def datagramReceived(self, datagram, address):

            print "Received:" + repr(datagram)

 

# Send multicast on 224.0.0.1:8005, on our dynamically allocated port

reactor.listenUDP(0, MulticastClientUDP()).write('UniqueID',

                                                 ('224.0.0.1', 8005))

reactor.run()

MulticastServer.py - listings/udp/MulticastClient.py

这是一个标准的UDP客户端的镜像实现。唯一的区别在于目标IP是一个组播地址。这个数据包将被分发到每一个在224.0.0.1和端口8005监听的服务器。注意客户端端口被指定为0,所以我们没有必要追踪客户端在监听那个客户端。

This is a mirror implementation of a standard UDP client. The only difference is that the destination IP is the multicast address. This datagram will be distributed to every server listening on 224.0.0.1 and port 8005. Note that the client port is specified as 0, as we have no need to keep track of what port the client is listening on.

Acknowledgements

Thank you to all contributors to this document, including:

  • Kyle Robertson, author of the explanation and examples of multicast

Index

Version: 8.2.0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值