概述

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 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.

和TCP不同,UDP没有连接。一个UDP套接字可以接受来自网络上的任何一台机器的报文,也可以发报文给任何一台主机。此外,报文可以以任意顺序到达,或者根本不到达(丢失),或者传输过程中发生重复。

既然没有连接,对于每一个UDP套机字,我们只需要使用一个协议的对象与之对应即可。然后可以用reactor来将协议对象绑定到UDP传输器(transport)上,使用 twisted.internet.interfaces.IReactorUDP 里面实现的reactor API。

DatagramProtocol

The class where you actually implement the protocol parsing and handling will usually be descended from twisted.internet.protocol.DatagramProtocol 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. When sending datagrams the destination address must be specified.

Here is a simple example:

我们的协议类,需要继承 twisted.internet.protocol.DatagramProtocol 类或者其子类。DatagramProtocol 类可以在网络上接受和发送报文。报文包括其发送地址。发送报文时必须指定接收地址。

下面是个简单的例子:

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

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

如你所见,协议跟reactor一起注册。这意味着如果在程序中使用协议,它可以持久化,因而有一个startProtocolstopProtocol 方法,分别在协议与套接字连接上和断开时调用。

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

协议的transport属性实现了twisted.internet.interfaces.IUDPTransport接口。注意host参数必需是一个ip地址,不是主机名。如果只有主机名,可用reactor.resolve()得到地址(参考wisted.internet.interfaces.IReactorCore.resolve).

Adopted Datagram Ports

端口复用(提供基于socket的端口的来决定监听的端口的灵活性)

It is also possible to add an existing SOCK_DGRAM file descriptor to the reactor using the adoptDatagramPort API.

Here is a simple example:

可以将一个已经存在的SOCK_DRAM文件描述符添加到reactor,通过使用adoptDatagramPort API.

下面是一个简单的例子:

import socket

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)) portSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Make the port non-blocking and start it listening.确保端口是非阻塞的,然后才开始绑定
portSocket.setblocking(False)
portSocket.bind(('127.0.0.1', 9999)) # Now pass the port file descriptor to the reactor
port = reactor.adoptDatagramPort(
portSocket.fileno(), socket.AF_INET, Echo()) # The portSocket should be cleaned up by the process that creates it.
portSocket.close() reactor.run()

  

Note

  • You must ensure that the socket is non-blocking before passing its file descriptor to adoptDatagramPort.
  • adoptDatagramPort cannot (currently) detect the family of the adopted socket so you must ensure that you pass the correct socket family argument.
  • The reactor will not shutdown the socket. It is the responsibility of the process that created the socket to shutdown and clean up the socket when it is no longer needed

注意:

  • 必须确保套接字是非阻塞的,才能将它的文件描述符传给adoptDatagramPort.
  • adoptDatagramPort(目前)不能检测采取的套接字的家族(family),因此务必确保falimy参数的正确赋值
  • reactor不会关闭套接字。创建套接字的进程应当在不使用之的情况下关闭然后清除套接字。

Connected UDP

"连接型"的UDP

A connected UDP socket is slightly different from a standard one as it can only send and receive datagrams to/from a single address. However this does not in any way imply a connection as 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 may provide notification of undelivered packages. This depends on many factors (almost all of which are out of the control of the application) but still presents certain benefits which occasionally make it useful.

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

"连接型"的UDP套接字和常规的套接字有点不同,它只能发送报文到固定地址,或者从该固定地址接受报文。这不是说报文基于连接,因为报文还是可能以任意的顺序抵达,且有可能端口的另外一端没有任何套接字监听。”连接型“的UDP套接字的好处是,它可以提供通知---哪些包没有被传输。这取决于很多因素(知乎所有的因素都超出程序的控制),但仍然还是在某些情况下会比较有用。

和常规的UDP协议不同,不需要指定目标地址,也不需要知道源地址,因为他们都来自套接字”被绑定“的地址。

from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor class Helloer(DatagramProtocol): def startProtocol(self):
host = "192.168.1.1"
port = 1234 self.transport.connect(host, port)
print "now we can only send to host %s port %d" % (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; 0表示任何端口,这种情形下我们
reactor.listenUDP(0, Helloer())
reactor.run()

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

注意到connect(),和write一样,只能接受ip地址,而不是主机名。通过主机名得到ip地址要使用reactor.resolve(),如下:

from twisted.internet import reactor

def gotIP(ip):
print "IP of 'example.com' is", ip
reactor.callLater(3, reactor.stop) reactor.resolve('example.com').addCallback(gotIP)
reactor.run()

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

”连接“到一个新的地址,在之前已经有”连接“的情况下,或者使得”连接“的端口变成”非连接“,这些在目前都是做不到的,将来也许可以。

Multicast UDP

组播UDP

Multicast allows a process to contact multiple hosts with a single packet, without knowing the specific IP address of any of the hosts. This is in contrast to normal, or unicast, UDP, where each datagram has a single IP as its destination. Multicast datagrams are sent to special multicast group addresses (in the IPv4 range 224.0.0.0 to 239.255.255.255), along with a corresponding port. In order to receive multicast datagrams, you must join that specific group address. However, any UDP socket can send to multicast addresses.

组播允许协议使用一个包联系多个主机,不需要知道这些主机的具体ip地址。这个常规的,单路通讯的udp不同,常规的单路通讯的udp的每个报文都有一个唯一的ip地址,作为它的目的地址。

组播的报文被送到一些特殊的组播地址(ipv4里面从224.0.0.0到239.255.255.255),附有一个相应的端口。 要接受组播报文,你必须加入到那个指定的组地址里面去。

然后,任何udp套接字都可以发送到组播地址。

MulticastServer.py

from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor class MulticastPingPong(DatagramProtocol): def startProtocol(self):
"""
Called after protocol has started listening.
"""
# Set the TTL>1 so multicast will cross router hops:设置TTL>1,以便跳过路由器,TTL定义最多跳几次
self.transport.setTTL(5)
# Join a specific multicast group:加入到一个具体的组播组
self.transport.joinGroup("228.0.0.5") def datagramReceived(self, datagram, address):
print "Datagram %s received from %s" % (repr(datagram), repr(address))
if datagram == "Client: Ping":
# Rather than replying to the group multicast address, we send the
# reply directly (unicast) to the originating port:
self.transport.write("Server: Pong", address) # We use listenMultiple=True so that we can run MulticastServer.py and
# MulticastClient.py on same machine: 使listenMultiple=True才能在同一台机器上运行客户端和服务器。
reactor.listenMulticast(8005, MulticastPingPong(),
listenMultiple=True)
reactor.run()

As with UDP, with multicast there is no server/client differentiation at the protocol level. Our server example is very simple and closely resembles a normal listenUDP protocol implementation. The main difference is that instead of listenUDPlistenMulticast is called with the port number. The server calls joinGroup to join a multicast group. A DatagramProtocol that is listening with multicast and has joined a group can receive multicast datagrams, but also unicast datagrams sent directly to its address. The server in the example above sends such a unicast message in reply to the multicast message it receives from the client.

使用udp,组播,客户端和服务器端在协议级别是没有差异的。上述服务器端代码比较简单,极似一个常规的 listenUDP协议的实现。主要区别在于,listenMulticast的调用中有端口。服务器端调用joinGroup加入到一个组播组。一个DatagramProtocol实例监听组播,加入到了可以接受组播报文的组中,但也可以接受直接发送给它的单路报文。上面的例子就发送了这样的一个单路广播的消息给它接受的消息的发送者。

MulticastClient.py

from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor class MulticastPingClient(DatagramProtocol): def startProtocol(self):
# Join the multicast address, so we can receive replies:
self.transport.joinGroup("228.0.0.5")
# Send to 228.0.0.5:8005 - all listeners on the multicast address
# (including us) will receive this message.
self.transport.write('Client: Ping', ("228.0.0.5", 8005)) def datagramReceived(self, datagram, address):
print "Datagram %s received from %s" % (repr(datagram), repr(address)) reactor.listenMulticast(8005, MulticastPingClient(), listenMultiple=True)
reactor.run()

  

Note that a multicast socket will have a default TTL (time to live) of 1. That is, datagrams won’t traverse more than one router hop, unless a higher TTL is set with setTTL. Other functionality provided by the multicast transport includes setOutgoingInterface andsetLoopbackMode – see IMulticastTransport for more information.

注意到一个组播的套接字默认的TTL为1。 就是说,报文不会跨任何一个路由器转发,除非通过setTTL设置了一个更大值。组播的传输器(transport)还有其他的函数比如setOutgoingInterface,以及setLoopbackMode - 具体请参考IMulticastTransport

Broadcast UDP

广播式UDP

Broadcast allows a different way of contacting several unknown hosts. Broadcasting via UDP sends a packet out to all hosts on the local network by sending to a magic broadcast address ("<broadcast>"). This broadcast is filtered by routers by default, and there are no “groups” like multicast, only different ports.

Broadcast is enabled by passing True to setBroadcastAllowed on the port. Checking the broadcast status can be done with getBroadcastAllowed on the port.

For a complete example of this feature, see udpbroadcast.py.

广播,提供了另外一种方式来联系一些未知的主机。通过UDP进行广播,将会把包发送给网络上的所有主机,只需要发送给一个神奇的广播地址("<broadcast>")。这个广播默认会被路由器过滤,没有类似于多路广播中的”组“的东东,只有不同的端口。

广播,只需要在端口上指定setBroadcastAllowed为True即可。检查端口上广播的状态可以通过getBroadcastAllowed来实现。

要知道完整的特性,请参考这里的例子 udpbroadcast.py.

twisted udp编程的更多相关文章

  1. Twisted UDP编程技术

    实战演练1:普通UDP UDP是一种无连接对等通信协议,没有服务器和客户端概念,通信的任何一方均可通过通信原语直接和其他方通信 1.相对于TCP,UDP编程只需定义DatagramProtocol子类 ...

  2. Linux学习四:UDP编程(上)

    关于UDP和TCP对比优缺,这里就不说了. 使用UDP代码所掉用的函数和用于TCP的函数非常类似,这主要因为套接口库在底层的TCP和UDP的函数上加了一层抽象,通过这层抽象使得编程更容易,但失去了一些 ...

  3. [C# 网络编程系列]专题七:UDP编程补充——UDP广播程序的实现

    转自:http://www.cnblogs.com/zhili/archive/2012/09/03/2666974.html 上次因为时间的关系,所以把上一个专题遗留下的一个问题在本专题中和大家分享 ...

  4. [C# 网络编程系列]专题六:UDP编程

    转自:http://www.cnblogs.com/zhili/archive/2012/09/01/2659167.html 引用: 前一个专题简单介绍了TCP编程的一些知识,UDP与TCP地位相当 ...

  5. Socket编程实践(12) --UDP编程基础

    UDP特点 无连接,面向数据报(基于消息,不会粘包)的传输数据服务; 不可靠(可能会丢包, 乱序, 反复), 但因此普通情况下UDP更加高效; UDP客户/服务器模型 UDP-API使用 #inclu ...

  6. 【Socket编程】通过Socket实现UDP编程

    通过Socket实现UDP编程 UDP通信: 1.UDP协议(用户数据报协议)是无连接.不可靠.无序的. 2.UDP协议以数据报作为数据传输的载体. 3.使用UDP进行数据传输时,首先需要将要传输的数 ...

  7. 网络编程之UDP编程

    网络编程之UDP编程 UDP协议是一种不可靠的网络协议,它在通信的2端各建立一个Socket,但是这个Socket之间并没有虚拟链路,这2个Socket只是发送和接受数据的对象,Java提供了Data ...

  8. 五十六、linux 编程——UDP 编程模型

    56.1 UDP 编程模型 56.1.1 编程模型 UDP 协议称为用户数据报文协议,可靠性比 TCP 低,但执行效率高 56.1.2 API (1)发送数据 函数参数: sockfs:套接字文件描述 ...

  9. 【网络编程1】网络编程基础-TCP、UDP编程

    网络基础知识 网络模型知识 OSI七层模型:(Open Systems Interconnection Reference Model)开放式通信系统互联参考模型,是国际标准化组织(ISO)提出的一个 ...

随机推荐

  1. javascript继承(八)-封装

    这个系列主要探讨的是javascript面向对象的编程,前面已经着重介绍了一下js的继承,下面想简单的说一下js如何实现封装的特性. 我们知道面向对象的语言实现封装是把成员变量和方法用一个类包围起来, ...

  2. 国内公共DNS

    DNS(Domain Name System,域名系统),因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串.通过主机名,最终 ...

  3. 每天一个linux命令(10):more命令

    more命令,功能类似 cat ,cat命令是整个文件的内容从上到下显示在屏幕上. more会以一页一页的显示方便使用者逐页阅读,而最基本的指令就是按空白键(space)就往下一页显示,按 b 键就会 ...

  4. The web application [/codeMarket] registered the JBDC driver[.........] but failed to unregister it when the web application was stopped. To prevent

    如果你报错了上面的这个严重,那么你的tomcat版本一定是在6.0.25之上的 原因:tomcat 6.025以后在sever.xml中引入了内存泄露侦测,对于垃圾回收不能处理的对像,它就会做日志. ...

  5. [转]Java静态方法为什么不能访问非静态方法

    非静态方法(不带static)可以访问静态方法(带static),但是反过来就不行,为什么呢? ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 publi ...

  6. 设计模式原来如此-代理模式(Proxy Pattern)

    代理模式(Proxy Pattern)是一个使用率非常高的模式,其定义如下:为其他对象提供一种代理以控制对这个对象的访问. 在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端 ...

  7. win8.1右键新建菜单添加新建php文件

    最近在学习php没使用IDE,一直使用编辑器,但每次新建文件都要手动该扩展名比较麻烦.于是想着能不能在右键新建菜单直接新建php文件.于是开始百度... 步骤一:win+R打开运行(管理员身份运行) ...

  8. 【CodeForces 602A】C - 特别水的题3-Two Bases

    http://acm.hust.edu.cn/vjudge/contest/view.action?cid=102271#problem/C Description After seeing the ...

  9. return view详解

    1.return View(); 返回值 类型:System.Web.Mvc.ViewResult将视图呈现给响应的 View() 结果. 注释 View() 类的此方法重载将返回一个具有空 View ...

  10. mac下使用minicom

    各种艰辛就不一一表过了,反正最后无奈的有捡起了minicom. 因为使用的brew,所以安装相对比较容易: brew install minicom 和Linux下一样的操作,先是查看硬件设备名称: ...