[python3.3]Python异步Socket编程【TCP】
生活随笔
收集整理的這篇文章主要介紹了
[python3.3]Python异步Socket编程【TCP】
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
參考:?http://www.cnblogs.com/snailrun/p/3805188.html
異步網(wǎng)絡(luò)據(jù)說(shuō)能極大的提高網(wǎng)絡(luò)server的連接速度,所以打算寫(xiě)一個(gè)專(zhuān)題,來(lái)學(xué)習(xí)和了解異步網(wǎng)絡(luò).因?yàn)镻ython有個(gè)非常出名的異步Lib:Twisted,所以就用Python來(lái)完成.?
OK,首先寫(xiě)一個(gè)pythone socket的server段,對(duì)開(kāi)放三個(gè)端口:10000,10001,10002.krondo的例子中是每個(gè)server綁定一個(gè)端口,測(cè)試的時(shí)候需要分別開(kāi)3個(gè)shell,分別運(yùn)行.這太麻煩了,就分別用三個(gè)Thread來(lái)運(yùn)行這些services.?
import optparse import os import socket import time from threading import Thread from io import StringIOtxt = '''1111 2222 3333 4444 '''# 服務(wù)端程序處理過(guò)程 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ā)送一個(gè)單詞后等待一會(huì)sock.close()print('\n')# 同時(shí)開(kāi)啟三個(gè)服務(wù)端線程,分別在三個(gè)端口監(jiān)聽(tīng) # 服務(wù)端程序?yàn)樽枞绞?#xff0c;只能一次服務(wù)于一個(gè)客戶端 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會(huì)被Python完全占用了
下面是一個(gè)client, 用阻塞方式,先后連接這個(gè)三個(gè)端口的server:?
from socket import *# 建立三個(gè)客戶端,分別連接三個(gè)不同的服務(wù)端程序, 接收服務(wù)端傳過(guò)來(lái)的數(shù)據(jù)并打印 # 這三個(gè)客戶端是阻塞方式通信的 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來(lái)讀取,代碼如下:
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) # 設(shè)置為非阻塞模式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:#運(yùn)用select來(lái)確保那些可讀取的異步socket可以立即開(kāi)始讀取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 # 保存每個(gè)sock接收到的數(shù)據(jù)elapsed = datetime.datetime.now() - startprint('Got poems in %s' %elapsed)
結(jié)果只需要2秒就完成了讀取任務(wù)。效率非常明顯啊。對(duì)客戶端的異步改造主要有兩點(diǎn):?
- 同步模式下,客戶端分別創(chuàng)建socket;而在異步模式下,client開(kāi)始就創(chuàng)建了所有的socket。
- 通過(guò)“sock.setblocking(0)”設(shè)置socket為異步模式。
- 通過(guò)Unix系統(tǒng)的select來(lái)返回可讀取socket信息
- 最為核心的是8行和26行。尤其是26行的select操作返回待讀取socket的列表。
總結(jié)
以上是生活随笔為你收集整理的[python3.3]Python异步Socket编程【TCP】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 无线投屏协议分类
- 下一篇: 检测python进程是否存活