twisted udp编程
概述
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一起注册。这意味着如果在程序中使用协议,它可以持久化,因而有一个startProtocol和stopProtocol 方法,分别在协议与套接字连接上和断开时调用。
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 listenUDP, listenMulticast 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编程的更多相关文章
- Twisted UDP编程技术
实战演练1:普通UDP UDP是一种无连接对等通信协议,没有服务器和客户端概念,通信的任何一方均可通过通信原语直接和其他方通信 1.相对于TCP,UDP编程只需定义DatagramProtocol子类 ...
- Linux学习四:UDP编程(上)
关于UDP和TCP对比优缺,这里就不说了. 使用UDP代码所掉用的函数和用于TCP的函数非常类似,这主要因为套接口库在底层的TCP和UDP的函数上加了一层抽象,通过这层抽象使得编程更容易,但失去了一些 ...
- [C# 网络编程系列]专题七:UDP编程补充——UDP广播程序的实现
转自:http://www.cnblogs.com/zhili/archive/2012/09/03/2666974.html 上次因为时间的关系,所以把上一个专题遗留下的一个问题在本专题中和大家分享 ...
- [C# 网络编程系列]专题六:UDP编程
转自:http://www.cnblogs.com/zhili/archive/2012/09/01/2659167.html 引用: 前一个专题简单介绍了TCP编程的一些知识,UDP与TCP地位相当 ...
- Socket编程实践(12) --UDP编程基础
UDP特点 无连接,面向数据报(基于消息,不会粘包)的传输数据服务; 不可靠(可能会丢包, 乱序, 反复), 但因此普通情况下UDP更加高效; UDP客户/服务器模型 UDP-API使用 #inclu ...
- 【Socket编程】通过Socket实现UDP编程
通过Socket实现UDP编程 UDP通信: 1.UDP协议(用户数据报协议)是无连接.不可靠.无序的. 2.UDP协议以数据报作为数据传输的载体. 3.使用UDP进行数据传输时,首先需要将要传输的数 ...
- 网络编程之UDP编程
网络编程之UDP编程 UDP协议是一种不可靠的网络协议,它在通信的2端各建立一个Socket,但是这个Socket之间并没有虚拟链路,这2个Socket只是发送和接受数据的对象,Java提供了Data ...
- 五十六、linux 编程——UDP 编程模型
56.1 UDP 编程模型 56.1.1 编程模型 UDP 协议称为用户数据报文协议,可靠性比 TCP 低,但执行效率高 56.1.2 API (1)发送数据 函数参数: sockfs:套接字文件描述 ...
- 【网络编程1】网络编程基础-TCP、UDP编程
网络基础知识 网络模型知识 OSI七层模型:(Open Systems Interconnection Reference Model)开放式通信系统互联参考模型,是国际标准化组织(ISO)提出的一个 ...
随机推荐
- JQuery ztree 异步加载实践
本来要做一个文件目录浏览界面,需要遍历所有的文件和目录,很显然一次性读取时很费时费力的一件事情. 因此就需要做异步加载.... 不过网上的几篇帖子还挺坑的!原始参考:JQuery异步加载实例,相对来说 ...
- UITableViewdataSourse的协议所有方法
UITableViewDataSource @required- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection ...
- Excel解析与导入导出
第三次结对编程作业 结对成员: 031302610黄志鹏 031302603 陈波 功能分析 1.将初始排课表excel导入系统数据库 2.将系统数据库的排课数据显示在web界面 实现思路 一.实现将 ...
- javascript 重难点(原型链 this) 理解总有一个过程,不要急,循序渐进!
开始补充: 1. 将函数定义作为对象的属性,称之为对象方法.2. this的指向是由它所在函数调用的上下文决定的(语境),而不是由它所在函数定义的上下文决定的.3. 因为当一个函数作为函数而不是方法来 ...
- tomcat虚拟路径的几种配置方法
一般我们都是直接引用webapps下面的web项目,如果我们要部署一个在其它地方的WEB项目,这就要在TOMCAT中设置虚拟路径了,Tomcat的加载web顺序是先加载 $Tomcat_home$\c ...
- ansible-2添加公钥
该文章摘自:http://www.fwqtg.net/%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E5%B7%A5%E5%85%B7ansible%E5 ...
- Linux_日志信息
一.httpd日志:/var/log/httpd1.软件位置:whereis httpd2.配置文件位置:/etc/httpd/conf/httpd.conf 二.mysql日志:/var/log 查 ...
- 9.Android之日期对话框DatePicker控件学习
设置日期对话框在手机经常用到,今天来学习下. 首先设置好布局文件:如图 xml对应代码 <?xml version="1.0" encoding="utf-8&qu ...
- 人工鱼群算法-python实现
AFSIndividual.py import numpy as np import ObjFunction import copy class AFSIndividual: "" ...
- 【干货】Laravel --Validate (表单验证) 使用实例
前言 : Laravel 提供了多种方法来验证应用输入数据.默认情况下,Laravel 的控制器基类使用ValidatesRequests trait,该trait提供了便利的方法通过各种功能强大的验 ...