IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> twisted 实现UDP服务 -> 正文阅读

[网络协议]twisted 实现UDP服务

?一:UDP基础知识:

????????udp没有连接的概念,udp套接字可以从网络上的任何服务器接收数据报,并将数据报发送到网络上的任何主机。数据报可以以任意顺序到达 or 根本不会到达 or 在传输过程中被复制。

? ? ? ? udp中可以使用connect系统调用,udp的connect和tcp的connect有着本质的区别,tcp中调用connect会引起三次握手然后client和server建立连接。udp中调用connect 内核没不干啥事儿,只是检查是否存在立即可知的错误(例如一个显然不可达到的目的地) 然后把对端的ip和端口记录一下而且。udp中可以多次调用connect,而tcp只能调用一次。

? ? ? ? 使用connect建立的udp连接 相比普通udp连接的优势:

优势1:提高发送效率比如发送2个报文,普通udp连接时内核的操作是:建立连接---->发送第一个报文---->断开连接--->建立连接--->发送第二个报文----->断开连接。而connect udp内核操作是:建立连接----->发送第一个报文----->发送第二个报文---->断开连接,每次发送报文内核都可能要做路由查询。从这来看 connect udp确实高效不少。

优势2:高并发服务中会增加系统稳定性。比如说A通过普通udp和 server B、C通信。B,C提供相同的服务,为了负载均衡,我们让A和B,C交替通信。A 与 B通信 ip_a:port_a <----> ip_b:port_b
A 与 C通信ip_a:port_a' <---->ip_c:port_c,在高并发情况下会发生port_a和port_a'相同,那么就有可能出现A等待B的报文却收到了C的报文。对于这种问题解决办法就是采用connect的udp通信方式,在A中建立2个udp,分别去connect B和C。

?注意事项:采用connect的UDP发送接受报文可以调用send,write和recv,read操作.当然也可以调用sendto,recvfrom。调用sendto的时候第五个参数必须是NULL,第六个参数是0.调recvfrom,recv,read系统调用只能获取到先前connect的ip+port发送的报文。

二:Twisted中UDP介绍

由于没有连接,所以对于每个udp套接字我们只能使用一个对象,一个协议。然后使用已经定义的接口twisted.internet.interfaces.IReactorUDP

class IReactorUDP(Interface):
    """
    UDP socket methods.
    """

    def listenUDP(
        port: int, protocol: "DatagramProtocol", interface: str, maxPacketSize: int
    ) -> "IListeningPort":
        """
        Connects a given L{DatagramProtocol} to the given numeric UDP port.

        @param port: A port number on which to listen.
        @param protocol: A L{DatagramProtocol} instance which will be
            connected to the given C{port}.
        @param interface: The local IPv4 or IPv6 address to which to bind;
            defaults to '', ie all IPv4 addresses.
        @param maxPacketSize: The maximum packet size to accept.

        @return: object which provides L{IListeningPort}.
        """

twisted中已经帮忙实现了udp协议:twisted.internet.protocol.DatagramProtocol

@implementer(interfaces.ILoggingContext)
class DatagramProtocol(AbstractDatagramProtocol):
    """
    Protocol for datagram-oriented transport, e.g. UDP.

    @type transport: L{None} or
        L{IUDPTransport<twisted.internet.interfaces.IUDPTransport>} provider
    @ivar transport: The transport with which this protocol is associated,
        if it is associated with one.
    """

    def logPrefix(self):
        """
        Return a prefix matching the class name, to identify log messages
        related to this protocol instance.
        """
        return self.__class__.__name__

    def connectionRefused(self):
        """
        Called due to error from write in connected mode.

        Note this is a result of ICMP message generated by *previous*
        write.
        """
class AbstractDatagramProtocol:
    """
    Abstract protocol for datagram-oriented transports, e.g. IP, ICMP, ARP,
    UDP.
    """

    transport = None
    numPorts = 0
    noisy = True

    def __getstate__(self):
        d = self.__dict__.copy()
        d["transport"] = None
        return d

    def doStart(self):
        """
        Make sure startProtocol is called.

        This will be called by makeConnection(), users should not call it.
        """
        if not self.numPorts:
            if self.noisy:
                log.msg("Starting protocol %s" % self)
            self.startProtocol()
        self.numPorts = self.numPorts + 1

    def doStop(self):
        """
        Make sure stopProtocol is called.

        This will be called by the port, users should not call it.
        """
        assert self.numPorts > 0
        self.numPorts = self.numPorts - 1
        self.transport = None
        if not self.numPorts:
            if self.noisy:
                log.msg("Stopping protocol %s" % self)
            self.stopProtocol()

    def startProtocol(self):
        """
        Called when a transport is connected to this protocol.

        Will only be called once, even if multiple ports are connected.
        """

    def stopProtocol(self):
        """
        Called when the transport is disconnected.

        Will only be called once, after all ports are disconnected.
        """

    def makeConnection(self, transport):
        """
        Make a connection to a transport and a server.

        This sets the 'transport' attribute of this DatagramProtocol, and calls the
        doStart() callback.
        """
        assert self.transport == None
        self.transport = transport
        self.doStart()

    def datagramReceived(self, datagram: bytes, addr):
        """
        Called when a datagram is received.

        @param datagram: the bytes received from the transport.
        @param addr: tuple of source of datagram.
        """

?server.py

from twisted.internet import protocol
from twisted.internet import reactor

class ServerProtocol(protocol.DatagramProtocol):

    def startProtocol(self):
        print("startProtocol")

    def stopProtocol(self):
        print("stopProtocol")

    def connectionRefused(self):
        print("connectionRefused")
    
    def datagramReceived(self, data, addr):
        print("received %r from %s" % (data, addr))
        self.transport.write(data, addr)

reactor.listenUDP(10004,ServerProtocol())
reactor.run()

client.py

from twisted.internet import protocol
from twisted.internet import reactor

class ClientProtocol(protocol.DatagramProtocol):

    def __init__(self,host,port):
        self.host = host
        self.port = port
    
    def startProtocol(self):
        print("startProtocol")
        self.transport.connect(self.host,self.port)
        self.transport.write(b"hello")

    def stopProtocol(self):
        print("stopProtocol")

    def connectionRefused(self):
        print("connectionRefused")
    
    def datagramReceived(self, data, addr):
        print("received %r from %s" % (data, addr))
        self.transport.write(data, addr)

reactor.listenUDP(0,ClientProtocol("192.168.0.102",10004))
reactor.run()

运行结果:

另外一种写法用的少

import socket
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor

class Echo(DatagramProtocol):
    def datagramReceived(self, data, addr):
        print("received %r from %s" % (data, addr))
        self.transport.write(data, addr)

portSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
portSocket.setblocking(False)
portSocket.bind(('127.0.0.1', 9999))
port = reactor.adoptDatagramPort(portSocket.fileno(), socket.AF_INET, Echo())
portSocket.close()
reactor.run()

connect()只接受IP,不接受未解析的主机名。?

from twisted.internet import reactor
def gotIP(ip):
    print("IP of 'localhost' is", ip)
    reactor.stop()
reactor.resolve('localhost').addCallback(gotIP)
reactor.run()
  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-03-06 13:32:18  更:2022-03-06 13:32:28 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 7:21:28-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码