UDP网络(UDP Networking) -- JerryMarx [2004-08-02 09:44:02]

1. 概要(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.

和TCP不同,UDP没有连接的概念.UDP socket可以接受任何网络服务器发来的数据报,也可以向任何网络地址发送数据报.而且,数据报可能以任何顺序到达,可能永远也不会到达,也可能重复到达.

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.

由于不存在多重连接,我们所有的UDP socket使用一个单独的对象,一个protocol.我们使用reactor把这个协议连接到UDP传输,使用twisted.internet.interface.IReactorUDP中提供的reactor API.

2. 数据报协议(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.

数据报协议(DatagramProtocol)类是基础中的基础,这个类实现了协议的解析和处理.这个类通常位于twisted.internet.protocol.DatagramProtocol.大部分协议或者直接继承自这个类或者继承自这个类的某个合适的子类.数据报协议类接收数据报,或者发送数据报.接收到的数据报包含数据报的发送地址,发送的数据报必须指定特定的目标地址.

Here is a simple example:

这里有个简单的例子:

   1 from twisted.internet.protocol import DatagramProtocol
   2 from twisted.internet import reactor
   3 
   4 class Echo(DatagramProtocol):
   5 
   6     def datagramReceived(self, data, (host, port)):
   7         print "received %r from %s:%d" % (data, host, port)
   8         self.transport.write(data, (host, port))
   9 
  10 reactor.listenUDP(9999, Echo())
  11 reactor.run()

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.

如你所见,protocol和reactor一起注册.这意味着如果它被添加到一个应用程序,它将持续存在.当协议被连接或者断开的时候它的方法twisted.internet.protocol.DatagramProtocol.startProtocol和twisted.internet.protocol.DatagramProtocol.stopProtocol会被调用.

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

Protocol的transport属性实现了twisted.internet.interfaces.IUDPTransport接口.注意参数host应该是一个IP地址,而不是域名(机器名).如果你只有域名(机器名)可用,可以调用reactor.resolve()得到IP地址(参见twisted.internet.interfaces.IReactorCore.resolve).

3. 连接UDP(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 is faster.

连接的UDP同标准UDP只有一些细微差别 -- 它只能和一个确定的地址通信(发送/接收数据报),但是这并不意味着我们有一个连接.数据报仍然可能以任何顺序到达,目标地址的端口甚至可能都没有打开.连接UDP的好处只是在于它更快一些.

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.

和标准UDP协议不同的是,我们不需要在发送数据报的时候指定地址,也不需要从数据报中得到来源地址的信息,因为我们只能和我们"连接"到的地址通信.

   1 from twisted.internet.protocol import DatagramProtocol
   2 from twisted.internet import reactor
   3 
   4 class Helloer(DatagramProtocol):
   5 
   6     def startProtocol(self):
   7         d = self.transport.connect("192.168.1.1", 1234)
   8         d.addCallback(self._cbConnected)
   9 
  10     def _cbConnected(self, (host, port)):
  11         print "we can only send to %s now" % str((host, port))
  12         self.transport.write("hello") # no need for address
  13 
  14     def datagramReceived(self, data, (host, port)):
  15         print "received %r from %s:%d" % (data, host, port)
  16 
  17 # 0 means any port, we don't care in this case
  18 reactor.listenUDP(0, Helloer())
  19 reactor.run()

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

注意connect()和write()一样只接受IP地址作为参数,不能使用域名.调用reactor.resolve()可以从域名得到IP地址.例如:

   1 from twisted.internet import reactor
   2 
   3 def gotIP(ip):
   4         print "IP of 'example.com' is", ip
   5 
   6 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.

在连接前一地址后连接到一个新地址,或者断开已经连接的端口目前还不支持,但是会在将来支持.

(目录)Index

  • 翻译 -- Jerry Marx 8/2/2004

Version: 1.3.0