天天看點

python網絡程式設計linux pdf_Python網絡程式設計:Linux epoll

原文位址:http://scotdoyle.com/python-epoll-howto.html

介紹

Python已于2.6版本添加通路Linux epoll庫的API。這篇教程使用Python 3簡要介紹如何使用Linux epoll。

阻塞Socket

例1是一個Pyhton服務端程式,它監聽8080端口,接收HTTP請求并将其列印到console,然後對HTTP請求進行回複。

#Example 1

import socket

EOL1 = b'\n\n'

EOL2 = b'\n\r\n'

response = b'HTTP/1.0 200 OK\r\nDate: Mon, 1 Jan 1996 01:01:01 GMT\r\n'

response += b'Content-Type: text/plain\r\nContent-Length: 13\r\n\r\n'

response += b'Hello, world!'

#建立socket

serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

serversocket.bind(('0.0.0.0', 8080))

serversocket.listen(1)

connectiontoclient, address = serversocket.accept()

request = b''

while EOL1 not in request and EOL2 not in request:

request += connectiontoclient.recv(1024)

print(request.decode())

connectiontoclient.send(response)

connectiontoclient.close()

serversocket.close()

下面的代碼添加了一個循環,不斷接收用戶端的請求直到被我們手動關閉。例2更清楚地展示了服務端建立的socket不直接與用戶端進行資料交換,而是服務端socket接收到來自用戶端的連接配接後,建立一個新的socket與該用戶端進行通信。

#Example 2

import socket

EOL1 = b'\n\n'

EOL2 = b'\n\r\n'

response = b'HTTP/1.0 200 OK\r\nDate: Mon, 1 Jan 1996 01:01:01 GMT\r\n'

response += b'Content-Type: text/plain\r\nContent-Length: 13\r\n\r\n'

response += b'Hello, world!'

serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

serversocket.bind(('0.0.0.0', 8080))

serversocket.listen(1)

try:

while True:

connectiontoclient, address = serversocket.accept()

request = b''

while EOL1 not in request and EOL2 not in request:

request += connectiontoclient.recv(1024)

print('-'*40 + '\n' + request.decode()[:-2])

connectiontoclient.send(response)

connectiontoclient.close()

#確定程式即使出現exception,socket也會被關閉

finally:

serversocket.close()

非阻塞Socket和Linux epoll的好處

上面兩個例子展示的都是阻塞socket。Python代碼執行到某行會停在那裡直到某一事件發生。如16行的accept()會被阻塞直到有一個用戶端請求連接配接。19行的recv()會被阻塞直到用戶端發送了資料(或沒有資料可讀取)。21行的send()會被阻塞直到所有要發送給用戶端的資料已經Linux被放入了傳輸隊列。

當一個服務端程式使用阻塞socket時,對于每一個用戶端,其經常使用一個線程甚至一個專門的程序進行通訊。服務端程式的主線程則主要包括監聽的被用來接受用戶端請求的socket。其每次接收一個來自用戶端的請求,并把新建立的用于和用戶端通信的socket傳給另外一個線程與用戶端進行互動。因為每個線程隻與一個用戶端進行通訊,某一個線程出現阻塞不會影響到其他線程執行的任務。

使用多線程和阻塞socket進行網絡程式設計寫出的代碼更加直覺、簡單,但是有不少缺點。多線程需要考慮到作業系統關于資源共享的常見問題,并且這種程式設計方式對單核CPU很不友好。

The C10K Problem讨論了若幹種處理并發連接配接的方法,比如使用異步socket。