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

  • 相关阅读:
    使用Aspose.Cell控件实现Excel高难度报表的生成(三)
    使用Aspose.Cell控件实现Excel高难度报表的生成(二)
    使用Aspose.Cell控件实现Excel高难度报表的生成(一)
    利用Aspose.Word控件和Aspose.Cell控件,实现Word文档和Excel文档的模板化导出
    新中新身份证阅读器不显示图片
    spring security 3 自定义认证,授权示例
    Spring Security教程
    Spring Security3实现,权限动态获取
    mybatis 做 insert操作的时候返回插入的那条数据的id
    如何在spring中获取request对象
  • 原文地址:https://www.cnblogs.com/Erick-L/p/7085793.html
Copyright © 2020-2023  润新知