[python3.3]Python异步Socket编程【TCP】
生活随笔
收集整理的這篇文章主要介紹了
[python3.3]Python异步Socket编程【TCP】
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
參考:?http://www.cnblogs.com/snailrun/p/3805188.html
異步網(wǎng)絡據(jù)說能極大的提高網(wǎng)絡server的連接速度,所以打算寫一個專題,來學習和了解異步網(wǎng)絡.因為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 from io import StringIOtxt = '''1111 2222 3333 4444 '''# 服務端程序處理過程 def server(listen_socket):while True:buf = 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()breaksock.sendall(line.encode('utf8')) # this is a blocking callprint('send bytes to client: %s' %line)except socket.error:sock.close()breaktime.sleep(0.5) # server每發(fā)送一個單詞后等待一會sock.close()print('\n')# 同時開啟三個服務端線程,分別在三個端口監(jiān)聽 # 服務端程序為阻塞方式,只能一次服務于一個客戶端 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 = ('127.0.0.1', port)listen_socket.bind(addres)listen_socket.listen(5)print("start listen at: %d" %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完全占用了
下面是一個client, 用阻塞方式,先后連接這個三個端口的server:?
from socket import *# 建立三個客戶端,分別連接三個不同的服務端程序, 接收服務端傳過來的數(shù)據(jù)并打印 # 這三個客戶端是阻塞方式通信的 if __name__ == '__main__':ports = [10000, 10001, 10002]for port in ports:address = ('127.0.0.1', port)sock = socket(AF_INET, SOCK_STREAM)sock.connect(address)poem = ''while True:data = sock.recv(4)if not data:sock.close()breakpoem += data.decode('utf8')print(poem)sock.close()
下面用異步的client來讀取,代碼如下:
import datetime, errno, optparse, select, socketdef connect(port):"""Connect to the given server and return a non-blocking socket."""address = ('127.0.0.1', port)sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)sock.connect(address)sock.setblocking(0) # 設置為非阻塞模式return sockdef format_address(address):host, port = addressreturn '%s:%s' % (host or '127.0.0.1', port)if __name__ == '__main__':ports = [10000, 10001, 10002]start = datetime.datetime.now()sockets = list(map(connect, ports))poems = dict.fromkeys(sockets, '') # socket -> accumulated poemsock2task = dict([(s, i + 1) for i, s in enumerate(sockets)])while sockets:#運用select來確保那些可讀取的異步socket可以立即開始讀取IO#OS不停的搜索目前可以read的socket,有的話就返回rlistrlist, _, _ = select.select(sockets, [], [])for sock in rlist:data = ''while True:try:new_data = sock.recv(1024)new_data = new_data.decode('utf8')except socket.error as e:if e.args[0] == errno.EWOULDBLOCK:breakraiseelse:if not new_data:breakelse:print(new_data)data += new_datatask_num = sock2task[sock]if not data:print(poems[sock]) # 打印sock接收到的數(shù)據(jù)sockets.remove(sock)sock.close()print('Task %d finished\n' % task_num)else:addr_fmt = format_address(sock.getpeername())msg = 'Task %d: got %d bytes of poetry from %s\n'print(msg % (task_num, len(data), addr_fmt))poems[sock] += data # 保存每個sock接收到的數(shù)據(jù)elapsed = datetime.datetime.now() - startprint('Got poems in %s' %elapsed)
結果只需要2秒就完成了讀取任務。效率非常明顯啊。對客戶端的異步改造主要有兩點:?
- 同步模式下,客戶端分別創(chuàng)建socket;而在異步模式下,client開始就創(chuàng)建了所有的socket。
- 通過“sock.setblocking(0)”設置socket為異步模式。
- 通過Unix系統(tǒng)的select來返回可讀取socket信息
- 最為核心的是8行和26行。尤其是26行的select操作返回待讀取socket的列表。
總結
以上是生活随笔為你收集整理的[python3.3]Python异步Socket编程【TCP】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 无线投屏协议分类
- 下一篇: Android NDK开发Crash错误