Twisted UDP编程技术

实战演练1:普通UDP

UDP是一种无连接对等通信协议,没有服务器和客户端概念,通信的任何一方均可通过通信原语直接和其他方通信

1、相对于TCP,UDP编程只需定义DatagramProtocol子类 无需定义Factory;完全基于twisted的方案

from twisted.internet.protocol import DatagramProtocol

from twisted.internet import reactor
import threading
import time
import datetime class Echo (DatagramProtocol): # Protocol子类,此处进行通信逻辑开发
def datagramReceived(self, datagram, addr):
print("got data from %s" % addr)
print(datagram.decode('utf8')) protocol = Echo() host = '127.0.0.1'
port = 8007 bStop = False
def routine(): # 每隔5秒向服务器发送消息
while not bStop:
# 第一个参数是发送的内容,第二个参数是 发送目的地的ip和端口号
protocol.transport.write (('hello,i am %s' % (datetime.datetime.now ())).encode ('utf8'), (host, port))
time.sleep (5) threading.Thread (target=routine).start () # 启动县城运行routine()函数
reactor.listenUDP (port, protocol)# 传入端口地址和处理该端口数据的DatagramProtocol子类 reactor.run () # 挂起运行 bStop = True # 通知routine线程退出

2、适配普通的socket对象的UDP编程

有时需要利用在其他模块中已经建立好的socket对象进行UDP编程,而无法完全基于twisted的方案

from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
import socket class Echo (DatagramProtocol): # DatagramProtocol子类
def datagramReceived(self, datagram, addr):
print("got data from %s" % addr)
print(datagram.decode('utf8')) protocol = Echo() host = '127.0.0.1'
port = 8007 # 建立普通socket对象
portSocket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
portSocket.setblocking(False) # 设为阻塞模式
portSocket.bind((host,port)) reactor.adoptDatagramPort(portSocket.fileno(),socket.AF_INET,protocol) # 适配普通socket portSocket.close() # 在启动reactor之前关闭普通socket对象
reactor.run()

实战演练2:Connect UDP

虽然UDP本身是无连接协议,但是编程接口仍然可以调用connect()函数,用来限制只与某地址和端口通信,当调用connect()函数,当需要向该地址发送数据时就不需要指定目标端口和地址了

Connect UDP本质上是数据报协议,虽然一定程度上实现了点对点链接

udp connected-udp tcp的比较
  UDP Connected UDP TCP
是否是点对点通信
数据包质检是否有序
发送是否可靠(发送方是否知晓数据已到达)
是否支持广播,组播

用Connected UDP改造后的UDP通信代码示例:

from twisted.internet.protocol import DatagramProtocol

from twisted.internet import reactor
import threading,time,datetime host = '127.0.0.1'
port = 8007 class Echo (DatagramProtocol): # DatagramProtocol子类
def startProtocol(self): # 连接成功后被调用
self.transport.connect(host,port) # 指定对方的地址和端口
print('连接已经创建') def datagramReceived(self, datagram, addr): # 收到数据时被调用
print(datagram.decode('utf8')) def connectionRefused(self): # 每次通信失败后调用
print('发送失败') def stopProtocol(self):
print('连接关闭') protocol = Echo() bStop = False def routine(factory): # 每隔5秒向服务器发送消息
while not bStop:
# 发送数据时只需传入数据,无需传入对方地址和端口
protocol.transport.write (('hello,i am %s' % (datetime.datetime.now ())).encode ('utf8'))
time.sleep (5) threading.Thread (target=routine,args=(factory,)).start () # 启动县城运行routine()函数
reactor.listenUDP (port, protocol)# 传入端口地址和处理该端口数据的DatagramProtocol子类 reactor.run () # 挂起运行 bStop = True # 通知routine线程退出

实战演练3:组播技术

在IPv4中 224.0.0.0 ~ 239.255.255.255 这个范围被用于组播管理,参与者在实际收发数据之前需要加入该地址范围中的一个ip地址,之后所有终端都可以用UDP的方式向组中的其他终端发送消息

twisted 中的组播编程代码示例如下:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor multicast_ip = '224.0.0.1' # 组播地址
port = 8001 # 端口 class Multicast (DatagramProtocol): # DatagramProtocol子类
def startProtocol(self): # 连接成功后被调用
self.transport.joinGroup(multicast_ip) # 加入组播组
self.transport.write(('Notify').encode('utf8'),(multicast_ip,port)) # 组播数据 def datagramReceived(self, datagram, addr): # 收到数据时被调用
print('datagram %s received from %s' % (repr(datagram),repr(addr)))
if datagram =='Notify':
self.transport.write(('Acknowlege').encode('utf8'),addr) # 单播回应 reactor.listenMulitcast(port,Multicast(),listenMultiple = True) # 组播监听
reactor.run() # 挂起运行

与joinGroup对应的,还有leaveGroup退出组播

上一篇:两句话概括cmd和amd的区别


下一篇:git操作:在CentOS7上面搭建GitLab服务器