twisted的tcp编程主要基于三个基础模块:Protocol、Factory、Transport。这三个模块时构成twisted服务器与客户端所有通信的基本

  • Protocol: 处理协议的类,这个类里的代码就是写你的协议要怎么处理通信过程中的发送和接收。大多数协议处理程序要么继承自此类,要么继承自他的子类。
  • Factory: 工厂模式的体现,是生产协议的工厂,即协议持久化存储在这。
  • Transport: 用来收发数据。

echo服务器

  • 服务器端
from twisted.internet import reactor,protocol


class Echo(protocol.Protocol):
    def connectionMade(self):
        self.client = self.transport.getPeer().host
        print("客户端连接成功:%s" % self.client)
    def dataReceived(self, data):
        #输出客户端传入内容
        print("客户端说: %s" % data.decode())        
        #返回数据给客户端
        self.transport.write(data)

class EchoFactory(protocol.Factory):
    
    #直接重写 生成 protocol 对象 的函数。
    def buildProtocol(self, addr):
        return Echo()
    # 第二种方法,重定义 protocol 为自定义的规则类
    # protocol = Echo

if __name__ == "__main__":
    # 监听5678端口
    reactor.listenTCP(5678,EchoFactory())
    reactor.run()
  • 客户端
from twisted.internet import reactor,protocol


class Echo(protocol.Protocol):
    def send(self):
        data = input("我说:")
        
        # 当输入exit时,退出客户端
        if data == "exit":
            reactor.stop()
        self.transport.write(data.encode())
    def connectionMade(self):
        # 建立连接后发送
        self.send()
    def dataReceived(self, data):
        print("服务器说: %s" % data.decode())
        # 回显消息并再次发送
        self.send()
       
class EchoFactory(protocol.ClientFactory):    
    #直接重写 生成 protocol 对象 的函数。
    def buildProtocol(self, addr):
        return Echo()
    # 第二种方法,重定义 protocol 为自定义的规则类
    # protocol = Echo

if __name__ == "__main__":
    # 建立与服务器的连接
    reactor.connectTCP('127.0.0.1',5678,EchoFactory())
    reactor.run()

transport

transport 代表两个通信结点之间的连接,transport负责描述连接的细节,比如连接是面向流式的还是面向数据包的,流控以及可靠性。transport实现了ITransport的接口:

  • write 以非阻塞的方式按顺序依次写到物理连接上
  • writeSequence 将一个字符串列表卸载物理连接上
  • loseConnection 将所有挂起的数据写入然后主动断开连接
  • getPeer -> host,port 取得连接中对端的地址信息
  • getHost -> host,port 取得连接轴本端的地址信息

protocol

Twisted protocol,以异步方式处理网络中的时间。protocol在事件从网络到达时对其进行响应,protocol实现了IProtocol,提供了以下接口:

  • factory 默认为None,协议工程实例对象,需要在构建协议对象时进行赋值,主要作用,可以在协议实例对象使用过程中,获取协议工厂实例对象。
  • connected 连接状态,默认为0,连接后为True
  • transport
  • dataReceived 当收到数据时调用,自动进行一次异步调用。
  • connectionLost 当客户端断开时,自动异步调用。
  • connectionMade 当连接建立时,自动异步调用

factory

协议工厂,用于实例化protocol 协议对象,并保存持久的公共信息,负责连接通信时建立连接,异界连接中断的处理,服务器端使用protocol.Factory,客户端使用protocol.ClientFactory。
factory:

  • protocol protocol的协议类,一般不使用,一帮使用buildProtocol来代替它
  • buildProtocol 创建protocol协议实例对象
  • startFactory 实例化协议对象时会自动调用这个方法。
  • stopFactory 协议对象撤销时会自动调用这个方法。
    ClientFactory:
  • buildProtocol 创建protocol协议实例对象
  • startedConnecting 连接建立时回调方法
  • clientConnectionLost 客户端连接服务器断开回调方法
  • clientConnectionFailed 刻画短连接服务器失败回调方法

聊天室实例

  • 服务器端
# -*- coding: utf-8 -*-
"""
Created on Mon Feb 21 10:46:21 2022

@author: xjmt

@内容: tcp编程1
"""

from twisted.internet import reactor,protocol


class Echo(protocol.Protocol):
    def __init__(self,factory=None):
        '''
        
        Parameters
        ----------
        factory : TYPE, optional
            DESCRIPTION. The default is None.

        Returns
        -------
        None.

        '''
        self.name = None
        self.factory = factory
        super().__init__()
        
    def connectionMade(self):
        '''
             客户端建立连接后提示,输入昵称

        Returns
        -------
        None.

        '''
        self.client = self.transport.getPeer()
        print("客户端连接成功:%s" % self.client.host)
        data = "请输入您的昵称:"
        self.transport.write(data.encode())
        
    def dataReceived(self, data):
        '''
             接收客户端信息,若客户端未命名,则将客户端输入信息作为用户名;
             若客户端已命名,则将向其他客户端发送输入的信息。

        Parameters
        ----------
        data : TYPE
            DESCRIPTION.

        Returns
        -------
        None.

        '''
        data=data.decode()
        if self.name == None and self not in self.factory.numbers:
            self.name = str(data)
            data = "欢迎【" + self.name + "】来到聊天室!"
            self.factory.numbers.append(self)
            self.transport.write(data.encode())
            data ="欢迎【" + self.name + "】上线了!"
        else:
            data = "【" + self.name + "】:" + data
            
            
        #返回数据给其他所有客户端 
        for number in self.factory.numbers:
            if number == self:
                continue            
            number.transport.write(data.encode())
        
        
    def connectionLost(self,reason):
        '''
            若客户端断开连接,则向所有成员发送下线信息

        Parameters
        ----------
        reason : TYPE
            DESCRIPTION.

        Returns
        -------
        None.

        '''
        # 向聊天室所有成员发送下线信息
        for number in self.factory.numbers:
            if number == self:
                continue
            data = "【" + self.name + "】已下线!"
            number.transport.write(data.encode())

class EchoFactory(protocol.Factory):
    #聊天室成员信息
    def __init__(self):
        self.numbers = []
    #直接重写 生成 protocol 对象 的函数。
    def buildProtocol(self, addr):  
        p = Echo()
        p.factory = self
        return p
    # 第二种方法,重定义 protocol 为自定义的规则类
    # protocol = Echo

if __name__ == "__main__":
    
    reactor.listenTCP(5678,EchoFactory())
    reactor.run()
  • 客户端
# -*- coding: utf-8 -*-
"""
Created on Tue Feb 22 09:22:24 2022
 
@author: xjmt
"""
 
from twisted.internet import reactor,protocol
import keyboard


 
class Echo(protocol.Protocol):
    def send(self):
        data = input()
        # 当输入exit时,退出客户端
        if data == "exit":
            reactor.stop()
        elif data != '' and data != '\n' and data != None:
            self.transport.write(data.encode())
        
        # 循环调用
        call = reactor.callLater(1,self.key_get)
            
    def key_get(self):
        keyboard.add_hotkey('enter',self.send)
        
    def connectionMade(self):
        # 建立连接后发送(发送与接收需要异步进行)
        print("欢迎使用本聊天室")
        call = reactor.callLater(1,self.key_get)
        
        
    def dataReceived(self, data):
        print(data.decode())
        # 回显消息并再次发送
        call = reactor.callLater(1,self.key_get)
        
 
class EchoFactory(protocol.ClientFactory):
    
    #直接重写 生成 protocol 对象 的函数。
    def buildProtocol(self, addr):
        return Echo()
    # 第二种方法,重定义 protocol 为自定义的规则类
    # protocol = Echo
 
if __name__ == "__main__":
    # 建立与服务器的连接
    reactor.connectTCP('127.0.0.1',5678,EchoFactory())
    reactor.run()

Q.E.D.