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()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Twisted是一个用于编写异步网络应用程序的Python框架。它提供了一系列的工具和模块,可以帮助开发者快速构建网络应用程序。使用Twisted可以构建客户端/服务器应用程序,处理网络协议和控制多种网络服务。要使用Twisted,可以安装Twisted库,然后使用Python编程语言编写应用程序,使用Twisted提供的API来控制网络应用程序的行为。 ### 回答2: Twisted是一个Python编写的异步网络编程框架,可以帮助我们构建高性能、可扩展的网络应用程序。下面是使用Twisted的一般步骤: 1. 安装Twisted:可以通过pip工具安装,运行命令`pip install Twisted`即可安装最新版本的Twisted。 2. 导入Twisted模块:在Python脚本中,使用`import twisted`语句导入Twisted模块。 3. 创建Twisted应用:使用Twisted提供的api,创建一个Twisted应用,并定义其行为和处理逻辑。 4. 定义回调函数:在Twisted应用中,需要定义一些回调函数来处理网络事件或其他异步操作。可以使用装饰器`@defer.inlineCallbacks`来定义一个异步的回调函数。 5. 运行Twisted应用:最后,使用`twisted.internet.reactor.run()`来运行Twisted应用,使其开始监听网络事件和处理异步操作。 在编写Twisted应用时,可以使用Twisted提供的各种协议和工具,如TCP协议、UDP协议、HTTP协议等,来建立和管理网络连接。可以使用Twisted提供的异步I/O操作,如发送和接收数据、定时器、延迟等,来处理异步任务和事件。 Twisted的API文档非常丰富,包含了各种使用示例和文档说明,可以通过官方网站或使用`help()`函数来查看Twisted的相关文档。 总之,Twisted是一个功能强大且灵活的网络编程工具,使用Twisted可以轻松地构建高性能、可扩展的网络应用程序。在使用Twisted时,需要了解Twisted的基本概念和原理,并按照上述步骤进行开发和调试。 ### 回答3: Twisted是一个用Python编写的事件驱动网络编程框架,它提供了一套强大的工具和API,用于快速开发高性能的网络应用程序。下面是使用Twisted的一些基本步骤: 1. 安装Twisted:首先,确保你的Python环境已经安装了Twisted库。你可以通过pip命令安装,例如:pip install twisted。 2. 导入Twisted:在你的Python程序中,首先要导入Twisted库,例如:from twisted.internet import reactor。 3. 创建网络服务对象:使用Twisted的事件驱动模型,你可以轻松地创建不同类型的网络服务对象,如TCP、UDP或HTTP。例如,如果你要创建一个TCP服务器,可以使用以下代码:from twisted.internet import protocol, reactor。 4. 定义协议类:定义一个继承自twisted.protocols.Protocol的类,该类将处理网络请求和响应。在这个类中,你可以重写一些方法,如connectionMade()、dataReceived()和connectionLost(),以实现相关的逻辑。 5. 创建监听器:为了让你的服务器可以接收连接请求,你需要创建一个监听器。例如,使用如下代码:reactor.listenTCP(port, protocol_instance)来监听指定端口并绑定协议实例。 6. 启动事件循环:最后,在你的程序中调用reactor.run()来启动事件循环,它将处理所有的网络事件和回调。当程序退出时,可以调用reactor.stop()来停止事件循环。 以上是使用Twisted进行网络编程的基本步骤。当然,Twisted还提供了许多其他强大功能和组件,如异步IO、deferreds、串行化任务和分布式计算等,可以根据具体的需求来使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值