• 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退出组播

  • 相关阅读:
    Java实现 蓝桥杯VIP 算法训练 字符串逆序
    Java实现 蓝桥杯VIP 算法训练 字符串逆序
    Java实现 蓝桥杯VIP 算法训练 最长字符串
    Java实现 蓝桥杯VIP 算法训练 最长字符串
    Java实现 蓝桥杯VIP 算法训练 最长字符串
    Java实现 蓝桥杯VIP 算法训练 最长字符串
    Java实现 蓝桥杯VIP 算法训练 最长字符串
    Java实现 蓝桥杯VIP 算法训练 成绩的等级输出
    Java实现 蓝桥杯VIP 算法训练 成绩的等级输出
    Qt 自定义model实现文件系统的文件名排序
  • 原文地址:https://www.cnblogs.com/Erick-L/p/7085793.html
Copyright © 2020-2023  润新知