【python】Twisted网络编程

Twisted

    • 什么是Twisted?
    • 为什么使用twisted?
    • Twisted 写TCP通信基本实例
      • - TCP服务端
      • - TCP客户端
    • Twisted的Deferred机制
      • Why Deferred?
      • Deferred TCP-ECHO客户端实现
        • - TCP client为例,

什么是Twisted?

Twisted是一种非阻塞的网络服务器技术,通过事件循环处理、回调机制来触发相应操作。
【相比socket通信,当有多个事件时,如果有一个事件阻塞,就都阻塞的情况。】

  • 异步处理:

类似小学数学题中的给定时间任务的合理安排,比如烧水和做饭两个任务,不用等烧完水再做饭,而是烧水中去做饭,一开始烧水,中间去做饭烧开时再管热水。

  • 【python】Twisted网络编程_第1张图片
  • twisted原理
    • reactor中心
    • 多任务轮询
    • 暂停循环回调执行操作

为什么使用twisted?

网络编程中,最基本的对协议的包装为socket库。socket通信方式如下:
【python】Twisted网络编程_第2张图片
Tcp协议中,服务端等待客户端发送数据rece()才能收到,否则就在阻塞等待。客户端也一样要等待服务端发送。这就是阻塞IO,浪费了很多性能。
Twisted 进行改进,提出非阻塞IO,不等待回复,而是不断轮询看是否收到。并根据情况进行状态切换操作,这就是异步处理.

  • 因此有多个客户端时,不用多线程实现,twisted内部单线程回调都能实现[^1]

Twisted 写TCP通信基本实例

  • Twisted使用方式
    • protocol中定义事件回调操作(根据需要找已有的方法即可)
    • 在factory中注册
    • 开启监听、轮询run

- TCP服务端

# TCP服务端
import twisted
import twisted.internet.protocol
import twisted.internet.reactor

SERVER_PORT = 8080 # 监听端口

class Server(protocol.Protocol): # 定义好事件的回调操作程序,twisted定义的事件,根据需要找到
	def connectionMade(self): # 客户端连接的时候触发
		print("客户端地址: %s" % self.transport.getPeer().host)
	
	def dataReceived(self. data): # 接收客户端数据
		print("[服务端]接收到数据 : %s" % data.decode("UTF-8")) # 输出接收到的数据
		self.transport.write(("[ECHO] %s" % data.decode("UTF-8")).encode("UTF-8")) # 回应

class DefaultServerFactory(protocol.Factory): # 定义处理工厂类,注册
	protocol = Server

def main():
	reactor.listenTCP(SERVER_PORT, DefaultServerFactory())  # 服务监听
	print("服务启动完毕,等待客户端连接。。。")
	reactor.run()  # 事件轮询

if __name__ == "__main__":
	main() 

- TCP客户端

import twisted
import twisted.internet.protocol
import twisted.internet.reactor
SERVER_HOST = "localhost"  # server 主机
SERVER_PORT = 8080  # server端口号

class Client(protocol.Protocol): # 定义客户端回调处理
	def connectionMade(self):
		print("服务器连接成功,可以进行数据交互,如果要结束通讯,则直接回车")
		self.send()
		
	def send(self):  # 自定义的数据发送方法
		input_data = input("请输入要发送的数据")
		if input_data: # 有数据输入
			self.transport.write(input_data.encode("UTF-8"))
		else:
			self.transport.loseConnection() # 关闭连接

class DefaultClientFactory(protocol.ClientFactory):
	protocol = Client
	clientConnectionLost = clientConnectionFailed = lambda self, connector, reason:reactor.stop()  # 只要连接失败 就关闭reactor

def main():
	reactor.connectTCP(SERVER_HOST, SERVER_PORT, DefaultClientFactory()) 
	reactor.run()

if __name__ == "__main__":
	main() 
connectionMade()等有的函数是Twisted定义好的方法,根据需要调用即可。

从代码中可以看出Twisted优势:在运行多个客户端时,相比socket,这里不需要进行并发(多线程)开发,全部执行流程都是单线程的运行模式(Python中的多线程有GIL全局锁问题)。Twisted内部会进行单线程回调实现,只需要找到对应的事件(方法)即可

Twisted的Deferred机制

Why Deferred?


线程不被长时间占用,而是另外开启线程执行这个长时任务,执行完告诉。

Deferred TCP-ECHO客户端实现

- TCP client为例,
import twisted
import twisted.internet.protocol
import twisted.internet.defer
import twisted.internet.reactor
import twisted.internet.threads
import time
SERVER_HOST = "localhost"  # server 主机
SERVER_PORT = 8080  # server端口号

class DeferClient(protocol.Protocol):  # 设置一个回调处理类
	def connectionMade(self):
		print("服务器连接成功,可以进行数据交互,如果要结束通讯,则直接回车")
		self.send()
	
	def send(self):  # 自定义的数据发送方法
		input_data = input("请输入要发送的数据")
		if input_data: # 有数据输入
			self.transport.write(input_data.encode("UTF-8"))
		else:
			self.transport.loseConnection() # 关闭连接
	
	def dataReceived(self, data): # 接收服务端发送的数据
		content = data.decode("utf-8")
		threads.deferToThread(self.handle_request, content).addCallback(self.handle_success) # 开启另一线程并用回调提示完成
	def handle_request(self, content): # 数据处理过程
		print("客户端对服务端的数据 %s 进行处理,此处会产生1s延迟..." % content) # 处理完毕后的信息输出
		time.sleep(1) # 模拟延迟
		return content # 返回处理结果
	def handle_success(self, result):
		print(处理完成,进行参数接收 %s" % result) # 处理完毕后的信息输出
	
	def handle_error(self, exp):
		print("程序出错,%s" % exp)

class DefaultClientFactory(protocol.ClientFactory):
	protocol = DeferClient
	clientConnectionLost = clientConnectionFailed = lambda self, connector, reason:reactor.stop()  # 只要连接失败 就关闭reactor
	
def main():
	reactor.connectTCP(SERVER_HOST, SERVER_PORT, DefaultClientFactory()) 
	reactor.run()

if __name__ == "__main__":
	main() 

解释
对数据的处理需要时间,想不只等待而是先去做别的:

def handle_request(self, content): # 数据处理过程
		print("客户端对服务端的数据 %s 进行处理,此处会产生1s延迟..." % content) # 处理完毕后的信息输出
		time.sleep(1) # 模拟延迟
		return content # 返回处理结果

因此把数据放到另一线程中进行处理,并用defer回调提示完成

import twisted.internet.threads
threads.deferToThread(self.handle_request, content).addCallback(self.handle_success) # 开启另一线程并用回调提示完成

注:以上总结自b站这个视频

你可能感兴趣的:(python,网络,python,服务器,twisted)