python的twisted

linux的五种IO模式

用户空间与内核空间:现代操作系统采用虚拟存储器,对32位操作系统而言,它的虚拟存储空间(寻址空间)为4G(2的32次方)。操作系统的核心是内核(kernel),独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。为了保证用户进程不能直接操作内核,保证内核的安全,操心系统将虚拟空间划分为两部分,一部分为内核空间,一部分为用户空间。

IO:即数据的读取(接收)或写入(发送)操作,通常用户进程中的一个完整IO分为两阶段:用户进程空间<-->内核空间、内核空间<-->设备空间(磁盘、网络等)。LINUX中进程无法直接操作I/O设备,必须通过系统调用请求kernel来协助完成I/O动作,内核会为每个I/O设备维护一个缓冲区。对于一个输入操作来说,进程IO系统调用后,内核会先看缓冲区中有没有相应的缓存数据,没有的话再到设备中读取,因为设备IO一般速度较慢,需要等待;内核缓冲区有数据则直接复制到进程空间。所以,对于一次IO访问(以网络输入操作为例)通常包括两个不同阶段:(1)等待内核缓冲区中数据准备(等待网络数据到达网卡→读取到内核缓冲区并准备好数据);(2)从内核缓冲区复制数据到进程空间。

阻塞IO:

当一个进程需要读取数据时,需要先从内核缓冲区中读取数据,当内核中数据还未准备好时,则该进程会被阻塞,直到数据准备好为止。

  • 进程挂起,不消耗CPU资源
  • 及时响应每个操作

非阻塞IO:

当一个进程需要读取数据时,需要先从内核缓存区中读取数据,当内核中数据还未准备好时,内核立即返回error,用户进程得知error后,会继续读取,直到数据准备好为止。

  • 进程轮询调用,消耗CPU资源

IO复用(事件驱动IO):

IO多路复用实现了一个进程对应多个IO操作(上述阻塞IO和非阻塞IO,一个用户进程只对应一个IO操作)。有select、poll、epoll三种模式,select/poll通过轮询来不断检测是否有描述符已就绪,select默认情况下支持最多监控1024个描述符,poll则没有这个限制(底层通过链表实现,可动态增加);epoll通过回调主动通知已有描述符已就绪,相比较select/poll效率有明显提升。

  • 还是同步IO,监听的IO在内核缓冲区都没有可读数据(所有描述符都没准备就绪),则该进程还是被阻塞
  • 多个进程注册IO后,只有一个select调用进程被阻塞(专一进程解决多个进程IO的阻塞问题)
  • Reactor模式

信号驱动的IO:

当进程发起一个IO操作,会向内核注册一个信号处理函数,然后进程返回不阻塞;当内核数据就绪时会发送一个信号给进程,进程便在信号处理函数中去主动将数据拷贝到用户内存。

  • 回调机制

异步IO:

当用户进程发起read操作后,立刻可以开始做其它事。而当内核收到一个asynchronous read后,首先会立刻返回,所以不会对用户进程产生block。然后内核等待数据准备完成后将数据拷贝到用户内存,当这一切都完成后,内核会给用户进程发送一个信号,告诉它read操作完成了,用户进程收到信号后获取已准备好的数据。

  • Proactor模式

Twisted

background:

单进程/单线程:依次执行,性能不高;多进程/多线程(并发):资源切换,系统调度,同步与等待带来的性能损耗;多线程/多进程仍解决不了阻塞IO;所以需要考虑异步IO(单一进程/线程下轮询机制,状态切换)

definition:

基于事件驱动的网络引擎框架,而非多线程模型。

reactor:

twisted的核心就是基于reactor的事件循环;reactor在单线程环境中调度多个事件源产生的事件到它们各自的事件处理例程中去;需要执行回调处理时reactor暂停循环,回调操作执行完毕后继续循环处理其他任务。

deferred:

deferrred对象包含一对回调链,一个是针对操作成功的回调,一个是针对操作失败的回调

interface:

ITransport

transport代表网络中两个通信结点之间的连接,负责描述连接的细节,TCP、UDP和Unix套接字可作为transport的例子。它们被设计为“满足最小功能单元,同时具有最大程度的可复用性”,而且从协议实现中分离出来,这让许多协议可以采用相同类型的传输;将transport从协议中分离出来也使得对这两个层次的测试变得更加简单。可以通过简单地写入一个字符串来模拟传输,用这种方式来检查。transport实现了ITransports接口。

IProtocol

tcp implementation:

# a tcp server with twisted
import twisted
#the Twisted event loop within Twisted, the loop which drives applications using Twisted.
import twisted.internet.reactor

SERVER_PORT = 8080

#Any protocol implementation, either client or server, should be a subclass of this class.
class server(twisted.internet.protocol.Protocol):
	#Called when a connection is made.
	def connectionMade(self):
		#Get the remote address of this connection.
		print("The client address: %s" %self.transport.getPeer().host)
	#Called when data is received.
	def dataReceived(self, data):
		print("Received data: %s" %data.decode('utf-8'))
		#Write some data to the physical connection, in sequence, in a non-blocking fashion.
		self.transport.write(("Echo: %s" %data.decode('utf-8')).encode('utf-8')) 
#A factory which produces protocols.
class server_factory(twisted.internet.protocol.Factory):
	protocol = server


def main():
	#Connects a given protocol factory to the given numeric TCP/IP port.

	twisted.internet.reactor.listenTCP(SERVER_PORT, server_factory()) 
	print("The server started...")
	#Fire 'startup' System Events, move the reactor to the 'running' state, then run the main loop until it is stopped with stop() or crash().
	twisted.internet.reactor.run()

if __name__ == "__main__":
	main()
#a tcp client with twisted
import twisted
import twisted.internet.protocol
import twisted.internet.reactor

SERVER_HOST = 'localhost'
SERVER_PORT = 8080

class client(twisted.internet.protocol.Protocol):
	def send(self):
		input_data = input("Please enter the message:")
		if input_data:
			self.transport.write(input_data.encode('utf-8'))
		else:
			#Close my connection, after writing all pending data.
			self.transport.loseConnection()

	def connectionMade(self):
		print('Connected successfully')
		self.send()
	def dataReceived(self, data):
		print(data)
		#self.send()

class client_factory(twisted.internet.protocol.ClientFactory):
	protocol = client
	#Called when an established connection is lost. / Called when a connection has failed to connect. 
	#clientConnectionLost = clientConnectionFailed = 
	#Fire 'shutdown' System Events, which will move the reactor to the 'stopped' state and cause reactor.run() to exit.


def main():
	#Connect a TCP client.
	twisted.internet.reactor.connectTCP(SERVER_HOST, SERVER_PORT, client_factory())
	twisted.internet.reactor.run()

if __name__ == "__main__":
	main()

Reference

5种IO模型、阻塞IO和非阻塞IO、同步IO和异步IO

Python Twisted介绍

猜你喜欢

转载自blog.csdn.net/qq_34276652/article/details/112739796