2017.07.12 Python網路編程之使用多工通訊端I/O

來源:互聯網
上載者:User

標籤:電話   簡單   返回   開始   any   stream   技術分享   roc   size   

1.在本章開始之前,需要先理解同步與非同步,阻塞與非阻塞的區別:

“阻塞”與"非阻塞"與"同步"與“非同步"不能簡單的從字面理解,提供一個從分布式系統角度的回答。
1.同步與非同步
同步和非同步關注的是訊息通訊機制 (synchronous communication/ asynchronous communication)
所謂同步,就是在發出一個*調用*時,在沒有得到結果之前,該*調用*就不返回。但是一旦調用返回,就得到傳回值了。
換句話說,就是由*調用者*主動等待這個*調用*的結果。

而非同步則是相反,*調用*在發出之後,這個調用就直接返回了,所以沒有返回結果。換句話說,當一個非同步程序呼叫發出後,調用者不會立刻得到結果。而是在*調用*發出後,*被調用者*通過狀態、通知來通知調用者,或通過回呼函數處理這個調用。

典型的非同步編程模型比如Node.js

舉個通俗的例子:
你打電話問書店老闆有沒有《分布式系統》這本書,如果是同步通訊機制,書店老闆會說,你稍等,”我查一下",然後開始查啊查,等查好了(可能是5秒,也可能是一天)告訴你結果(返回結果)。
而非同步通訊機制,書店老闆直接告訴你我查一下啊,查好了打電話給你,然後直接掛電話了(不返回結果)。然後查好了,他會主動打電話給你。在這裡老闆通過“回電”這種方式來回調。

2. 阻塞與非阻塞
阻塞和非阻塞關注的是程式在等待調用結果(訊息,傳回值)時的狀態.

阻塞調用是指調用結果返回之前,當前線程會被掛起。調用線程只有在得到結果之後才會返回。
非阻塞調用指在不能立刻得到結果之前,該調用不會阻塞當前線程。

還是上面的例子,
你打電話問書店老闆有沒有《分布式系統》這本書,你如果是阻塞式調用,你會一直把自己“掛起”,直到得到這本書有沒有的結果,如果是非阻塞式調用,你不管老闆有沒有告訴你,你自己先一邊去玩了, 當然你也要偶爾過幾分鐘check一下老闆有沒有返回結果。
在這裡阻塞與非阻塞與是否同步非同步無關。跟老闆通過什麼方式回答你結果無關。

 

 

2.在通訊端伺服器程式中使用ForkingMixIn:

 

# -*- coding: UTF-8 -*-
# 編寫一個非同步Python通訊端伺服器程式,伺服器處理用戶端發出的請求時不能阻塞,
# 因此要找一種機制來單獨處理每個用戶端,
# Python2.7中的SocketServer模組提供了兩個實用類:ForkingMixIn和ThreadingMixIn,
# ForkingMixIn會為每一個用戶端請求派生一個新進程
# !usr/bin/env python
# Python Network Programming Cookbook --Chapter -1
# This program is optimized for Python 2.7
# It may run on any other version with/without modifications

import os
import socket
import threading
import SocketServer

SERVER_HOST=‘localhost‘
SERVER_PORT=0
BUF_SIZE=1024
ECHO_MSG=‘Hello echo server‘

class ForkingClient():
"""一個forKing服務的用戶端測試"""
def __init__(self,ip,port):
self.sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
self.sock.connect((ip,port))

def run(self):
"""用戶端和伺服器互動"""
current_process_id=os.getpid()
print ‘PID%s 發送回顯訊息到伺服器:"%s"‘ %(current_process_id,ECHO_MSG)

sent_data_length=self.sock.send(ECHO_MSG)
print "發送:%d characters ,so far....." %sent_data_length

response=self.sock.recv(BUF_SIZE)
print "PID%s 收到 :%s" %(current_process_id,response[5:])

def shutdown(self):
"""清除用戶端的通訊端"""
self.sock.close()

class ForkingServerRequestHandler(SocketServer.BaseRequestHandler):
def handle(self):
data=self.request.recv(BUF_SIZE)
current_process_id=os.getppid()
response=‘%s :%s‘ %(current_process_id,data)
print "伺服器發送回應[當前的進程ID:data]=[%s]" %response
self.request.send(response)
return

class ForkingServer(SocketServer.ForkingMixIn,SocketServer.TCPServer):
"""沒什麼可以添加的這裡,繼承父類中必須的屬性"""
pass

def main():
server=ForkingServer((SERVER_HOST,SERVER_PORT),ForkingServerRequestHandler)
ip,port=server.server_address
server_thread=threading.Thread(target=server.serve_forever)
server_thread.setDaemon(True)
server_thread.start()
print ‘伺服器loop運行PID:%s‘ %os.getpid()

client1=ForkingClient(ip,port)
client1.run()

client2=ForkingClient(ip,port)
client2.run()

server.shutdown()
client1.shutdown()
client2.shutdown()
server.socket.close()


if __name__==‘__main__‘:
main()


程式由3部分組成:

建立一個 SocketServer 所要做的大部分工作是定義一個請求處理( request handler )類。
它是 SocktServer 模組裡 BaseRequestHandler 類的子類,並且每一個 request handler 對象在用戶端串連到服務端時處理著一個用戶端的請求。
這是在請求處理的 handle 方法裡實現的。

無論什麼時候串連到這個服務端, TCPServer 類將傳遞正確的變數來建立一個新的  RequestHandler ,並調用 handle 方法來處理請求。

下面是伺服器類和main主方法:

process_request會繼承自ThreadingMixIn或者ForkingMixIn,對每個request建立線程,然後由線程調用finish_request
運行結果:

 

 
 

2017.07.12 Python網路編程之使用多工通訊端I/O

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.