使用Twisted进行TCP编程,主要是针对Protocol、Factory、ClientFactory等类进行编程
Protocol子类
针对每个客户端连接,Twisted框架建立一个Protocol子类的实例管理该连接。需要编写该子类,使其能处理3个基本事件响应函数
- connectionMade():当连接建立时调用
- dataReceived():当收到客户端数据时调用
- connectionLost():当连接断开时调用
Factory
Factory子类起到对Protocol类的管理作用,当有新客户端连接时,框架调用Factory.buildProtocol(),使得程序员可以在这里创建Protocol子类的实例
- buildProtocol:关键函数,创建Protocol子类,Factory子类需要重写该函数
# code:utf8
from typing import Tuple
from twisted.internet.protocol import Protocol, connectionDone,Factory
from twisted.internet.endpoints import TCP4ServerEndpoint
from twisted.python import failure
from twisted.internet import reactor
from datetime import datetime
clients = []
class Spreader(Protocol):
'''
class tcp connect
'''
def __init__(self,factory):
'''
构造函数
:param factory:
'''
self.factory = factory
def connectionMade(self):
self.factory.numProtocols = self.factory.numProtocols+1
str_msg = "欢迎来到Spread Site,你是第%d个客户端\n"%(self.factory.numProtocols)
self.transport.write(str_msg.encode('utf8'))
print('new connect:%d'%self.factory.numProtocols)
clients.append(self)
def dataReceived(self, data: bytes):
if data.decode('utf8') == 'close':
self.transport.loseConnection()
else:
print(data.decode('utf8'))
str_msg = 'hello , i am %s %s'%('server',datetime.now())
self.transport.write(str_msg.encode('utf8'))
def connectionLost(self, reason: failure.Failure = connectionDone):
self.factory.numProtocols = self.factory.numProtocols-1
clients.remove(self)
print('lost connect : %d '%self.factory.numProtocols)
class SpreadFactory(Factory):
def __init__(self):
self.numProtocols = 0
def buildProtocol(self, addr: Tuple[str, int]) -> "Protocol":
'''
创建Protocol 子类
:param addr:
:return:
'''
return Spreader(self)
endpoint = TCP4ServerEndpoint(reactor,8007)
endpoint.listen(SpreadFactory())
reactor.run()
ClientFactory
比Factory多了三个函数
- startedConnecting():开始连接的时候调用
- clientConnectionLost():连接断开时调用
- clientConnectionFailed():连接失败时调用
客户端使用twisted.internet.reactor.connectTCP()连接指定的服务器
# code:utf8
import sys
import threading
import time
from datetime import datetime
from typing import Tuple
from twisted.internet import reactor
from twisted.internet.protocol import Protocol, ClientFactory, connectionDone
from twisted.python import failure
class Echo(Protocol):
def __init__(self):
self.connected = False
def connectionLost(self, reason: failure.Failure = connectionDone):
self.connected=False
def connectionMade(self):
self.connected=True
def dataReceived(self, data: bytes):
print(data.decode('utf8'))
def close(self):
'''
关闭连接
:return:
'''
self.transport.loseConnection()
class EchoClientFactory(ClientFactory):
def __init__(self):
self.protocol = None
def startedConnecting(self, connector):
'''
事件:开始连接的时候调用
:param connector:
:return:
'''
print('Started to connect.')
def buildProtocol(self, addr: Tuple[str, int]) -> "Protocol":
'''
创建客户端Protocol子类
:param addr:
:return:
'''
print('Connected')
self.protocol = Echo()
return self.protocol
def clientConnectionFailed(self, connector, reason):
'''
事件:连接失败时调用
:param connector:
:param reason:
:return:
'''
print('Connected failed. Reason :',reason)
def clientConnectionLost(self, connector, reason):
'''
事件:连接断开时调用
:param connector:
:param reason:
:return:
'''
print('Lost Connection . Reason :',reason)
b_stop = False
def routeine(factory:EchoClientFactory):
while not b_stop:
if factory.protocol and factory.protocol.connected:
str_msg = 'hello , i am %s %s'%(sys.argv[0],datetime.now())
factory.protocol.transport.write(str_msg.encode('utf8'))
time.sleep(5)
host = '127.0.0.1'
port=8007
factory = EchoClientFactory()
reactor.connectTCP(host,port,factory)
threading.Thread(target=routeine,args=(factory,)).start()
reactor.run()
b_stop = True
客户端与服务器的编程模式一致
TCP Server 示例
以下代码可以不用定义Factory子类,不用TCP4ServerEndpoint启动服务
factory = protocol.Factory() factory.protocol = TSServerProtocol reactor.listenTCP(PORT,factory) reactor.run()
Protocol 子类只需要实现connectionMade、connectionLost、dataReceived事件定义和必要的自定义函数即可
# coding:utf8
import zlib
from tools.sys_log import logger
from twisted.internet import protocol,reactor
PORT = 8006
class TSServerProtocol(protocol.Protocol):
'''
server handler
'''
__buffer_cache = None
def connectionMade(self):
'''
client first connected
'''
client_info = self.transport.getPeer() # 获取客户端的IP和端口
# ip = client_info.host # str
# port = client_inof.port # int
logger.info(f'connect from {client_info}')
def dataReceived(self, data: bytes):
'''
receive cilent data
'''
if self.__buffer_cache == None:
self.__buffer_cache = data
else:
self.__buffer_cache+=data
# 解析数据,对数进行处理
print(self.__buffer_cache.decode('utf8'))
self.__buffer_cache = None
def connectionLost(self, reason):
'''
client close
'''
client_info = self.transport.getPeer()
logger.info(f'lost connection from {client_info}:{reason}')
self.__buffer_cache = None
return
def writeBuff(self,data:bytes):
"""_summary_
send buff to client
Args:
data (bytes): buff
"""
self.transport.write(data)
if __name__ =='__main__':
logger.info('server start ......')
factory = protocol.Factory()
factory.protocol = TSServerProtocol
reactor.listenTCP(PORT,factory)
reactor.run()