前面第五篇(一)中的一個Socket例子其實就是單線程的,即Server端一次只能接受來自一個Client端的鏈接,爲了更好的說明socket單線程和阻塞模式,下面對前面的例子作修改。
python
1.單線程+阻塞+交互式多線程
前面的例子是單線程阻塞和非交互式的,如今改寫爲交互式的,即不會執行一次就結束,但願達到的效果是,發送的數據由User輸入,而後Server端進行接收。
併發
Server端:與上個例子同樣,並無什麼變化socket
import socket #導入socket類 HOST ='' #定義偵聽本地地址口(多個IP地址狀況下),這裏表示偵聽全部,也能夠寫成0.0.0.0 PORT = 50007 #Server端開放的服務端口 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #選擇Socket類型和Socket數據包類型 s.bind((HOST, PORT)) #綁定IP地址和端口 s.listen(1) #定義偵聽數開始偵聽(實際上並無效果) conn, addr = s.accept() #定義實例,accept()函數的返回值能夠看上面的socket函數說明 print 'Connected by', addr while 1: data = conn.recv(1024) #接受套接字的數據 if not data:break #若是沒有數據接收,則斷開鏈接 print 'revc:',data #發送接收到的數據 conn.sendall(data) #發送接收到的數據 conn.close() #關閉套接字
Client端:ide
import socket HOST = '192.168.1.13' PORT = 50007 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT)) while True: user_input = raw_input('msg to send:').strip() #由User輸入要發送的數據 s.sendall(user_input) data = s.recv(1024) print 'Received', repr(data) s.close()
演示:函數
步驟1:Server端運行服務端程序spa
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day5$ python server4.py ===>光標在此到處於等待狀態
步驟2:Client A端運行客戶端程序線程
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day5$ python client4.py msg to send:The first msg. ===>User輸入數據 Received 'The first msg.' ===>Server端返回的數據 msg to send:The second msg. Received 'The second msg.' msg to send:The third msg. Received 'The third msg.' msg to send:I'm A. Received "I'm A." msg to send: ===>繼續等待User輸入數據
步驟3:在Server端中觀察現象orm
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day5/[2]sec_4_ver2(單線程,交互式,阻塞模 通常演示)$ python server4.py Connected by ('192.168.1.13', 52645) revc: The first msg. ===>接收到用戶發送的數據 revc: The second msg. revc: The third msg. revc: I'm A. ===>光標在此到處於等待狀態
若是此時有另外一個Client B端再鏈接進來,會有下面的狀況:
server
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day5$ python client4.py msg to send:I'm B ===>光標在此到處於等待狀態
這時若是在Client A端斷開鏈接,則服務端也會關閉套接字,Client B端發送的數據仍然沒法被Server端接收。
此時服務端即出現阻塞狀況,由於服務端還和Client A處於鏈接狀態,沒法接收Client B發送的數據,這也說明了此時的Server端是單線程的。
2.單線程+阻塞+交互式的進階演示
把上面的例子中的代碼再作進一步的修改,以使得阻塞模式的現象更加明顯。
Server端:
import socket HOST ='' PORT = 50007 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind((HOST, PORT)) s.listen(1) while 1: conn, addr = s.accept() #在循環中接受Client端鏈接的請求 print 'Connected by', addr while True: #再作一個內部的循環 data = conn.recv(1024) print 'Received',data if not data:break conn.sendall(data) conn.close()
Client端:與前面例子的代碼同樣
import socket HOST = '192.168.1.13' PORT = 50007 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT)) while True: user_input = raw_input('msg to send:').strip() s.sendall(user_input) data = s.recv(1024) print 'Received', repr(data) s.close()
演示:
步驟1:Server端運行服務端程序
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day5$ python server4.py ===>光標在此到處於等待狀態
步驟2:Client A端運行客戶端程序
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day5$ python client4.py msg to send:Hello! Received 'Hello!' msg to send:I'm Client A. Received "I'm Client A." msg to send: ===>繼續等待User輸入數據
步驟3:在Server端中觀察現象
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day5$ python server4.py Connected by ('192.168.1.13', 52647) Received Hello! Received I'm Client A. ===>光標在此到處於等待狀態
若是此時有另外一個Client B端再鏈接進來,會有下面的狀況:
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day5$ python client4.py msg to send:I'm Client B. ===>光標在此到處於等待狀態
Server端的狀態依然爲:
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day5$ python server4.py Connected by ('192.168.1.13', 52647) Received Hello! Received I'm Client A. ===>光標在此到處於等待狀態
這時試圖把Client A端斷開:
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day5$ python client4.py msg to send:Hello! Received 'Hello!' msg to send:I'm Client A. Received "I'm Client A." msg to send:^CTraceback (most recent call last): File "client4.py", line 10, in <module> user_input = raw_input('msg to send:').strip() KeyboardInterrupt
再看看Server端的狀況:
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day5$ python server4.py Connected by ('192.168.1.13', 52647) Received Hello! Received I'm Client A. Received Connected by ('192.168.1.13', 52648) Received I'm Client B. ===>成功接收到來自Client B端發送的數據 ===>光標在此到處於等待狀態
再看看Client B端的狀況:
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day5$ python client4.py msg to send:I'm Client B. Received "I'm Client B." msg to send: ===>光標在此到處於等待狀態
以上的現象,再根據Server端的程序代碼,就能夠很是好理解單線程模式和阻塞的細節狀況了,在這裏是這樣的:Server端接受Client A端的鏈接後,即把接受鏈接的線程釋放,但此時仍然佔用接收和發送數據的線程,因此Client B端雖然能夠鏈接上Server端,但數據是沒法成功被Server端接收的;當Client A端斷開與Server端的鏈接後,Server端的接收和發送數據的線程當即被釋放,以後就能夠正常接收來自Client B端發送的數據了。
單線程,即數據的串行發送,會致使阻塞,上面的兩個例子就很是好地演示了這個阻塞的過程,若是要解決這個問題,固然在Server端就須要支持多線程,即數據折併發。