视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
Python异步网络探
2020-11-27 14:27:22 责编:小采
文档


异步网络据说能极大的提高网络server的连接速度,所以打算写一个专题,来学习和了解异步网络.因为Python有个非常出名的异步Lib:Twisted,所以就用Python来完成.

OK,首先写一个pythone socket的server段,对开放三个端口:10000,10001,10002.krondo的例子中是每个server绑定一个端口,测试的时候需要分别开3个shell,分别运行.这太麻烦了,就分别用三个Thread来运行这些services.

import optparse
import os
import socket
import time
from threading import Thread
import StringIO
 
txt = '''1111
2222
3333
4444
'''
 
def server(listen_socket):
 while True:
 buf = StringIO.StringIO(txt)
 sock, addr = listen_socket.accept()
 print 'Somebody at %s wants poetry!' % (addr,)
 while True:
 try:
 line = buf.readline().strip()
 if not line:
 sock.close()
 break
 sock.sendall(line) # this is a blocking call
 print 'send bytes to client:%s' % line
 #sock.close()
 except socket.error:
 sock.close()
 break
 time.sleep(1) #server和client连接后,server会故意每发送一个单词后等待一秒钟后再发送另一个单词
 
 
def main():
 ports = [10000, 10001, 10002]
 for port in ports:
 listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
 addres = (str('127.0.0.1'), port)
 listen_socket.bind(addres)
 listen_socket.listen(5)
 print "start listen at:%s" % (port,)
 worker = Thread(target = server, args = [listen_socket])
 worker.setDaemon(True)
 worker.start()
 
 
if __name__ == '__main__':
 main()
 while True:
 time.sleep(0.1) #如果不sleep的话,CPU会被Python完全占用了
 pass

下面是一个client,没有才用异步网络,连接这个三个端口的server:

import socket
 
 
if __name__ == '__main__':
 ports = [10000, 10001, 10002]
 for port in ports:
 address = (str('127.0.0.1'), port)
 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 sock.connect(address)
 poem = ''
 while True:
 data = sock.recv(4)
 if not data:
 sock.close()
 break
 poem += data
 print poem

下面用异步的client来读取,代码如下:

import datetime, errno, optparse, select, socket
 
def connect(port):
 """Connect to the given server and return a non-blocking socket."""
 address = (str('127.0.0.1'), port)
 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 sock.connect(address)
 sock.setblocking(0)
 return sock
 
def format_address(address):
 host, port = address
 return '%s:%s' % (host or '127.0.0.1', port)
 
if __name__ == '__main__':
 ports = [10000, 10001, 10002]
 start = datetime.datetime.now()
 
 sockets = map(connect, ports)
 poems = dict.fromkeys(sockets, '') # socket -> accumulated poem 
 
 # socket -> task numbers
 sock2task = dict([(s, i + 1) for i, s in enumerate(sockets)])
 sockets = list(sockets) # make a copy
 
 while sockets:
 #运用select来确保那些可读取的异步socket可以立即开始读取IO
 #OS不停的搜索目前可以read的socket,有的话就返回rlist
 rlist, _, _ = select.select(sockets, [], [])
 for sock in rlist:
 data = ''
 while True:
 try:
 new_data = sock.recv(1024)
 except socket.error, e:
 if e.args[0] == errno.EWOULDBLOCK:
 break
 raise
 else:
 if not new_data:
 break
 else:
 print new_data
 data += new_data
 
 task_num = sock2task[sock]
 if not data:
 sockets.remove(sock)
 sock.close()
 print 'Task %d finished' % task_num
 else:
 addr_fmt = format_address(sock.getpeername())
 msg = 'Task %d: got %d bytes of poetry from %s'
 print msg % (task_num, len(data), addr_fmt)
 
 poems[sock] += data
 
 elapsed = datetime.datetime.now() - start
 print 'Got poems in %s' % elapsed

结果只需要4秒就完成了读取任务。效率是刚才同步socket的三倍。对客户端的异步改造主要有两点:

同步模式下,客户端分别创建socket;而在异步模式下,client开始就创建了所有的socket。

通过“sock.setblocking(0)”设置socket为异步模式。

通过Unix系统的select俩返回可读取IO

最为核心的是26行和29行。尤其是29行的select操作返回待读取socket的列表。

下载本文
显示全文
专题