socket的阻塞或同步程式設計
一、使用socket
網 絡程式設計中最基本的部分就是socket(套接字)。socket有兩種:服務端socket和客戶端 socket。在你建立了乙個服務端socket之 後,你告訴它去等待連線。然後它將監聽某個網路位址(形如:***.***.***.***:***) 直到客戶端連線。然後這兩端就可以通訊了。
處理客戶端socket通常比處理服務端socket要容易一點,因為服務端必須時刻準備處理來自客戶端的連線,並且它必須處理多個連線,而客戶端只需要簡單的連線,然後做點什麼,然後斷開連線。
實 例化乙個socket時,可以指定三個引數:位址系列(預設為socket.af_inet)、流socket(這是個預設值: socket.sock_stream)或資料報socket(socket.sock_dgram)、協議(預設值是0)。對於簡單的socket, 你可以不指定任何引數而全部使用預設值。
服務端socket在使用bind方法之後呼叫listen方法去監聽乙個給定的位址。然後,客 戶端socket就可以通過使用connect方法(connect方法所使用的位址引數與bind相同)去連線服務端。listen方法要求乙個引數, 這個引數就是等待連線佇列中所能包含的連線數。
一旦服務端socket呼叫了listen方法,就進入了臨聽狀態,然後通常使用乙個無限 的迴圈:1、開始接受客房端的連線,這通過呼叫accept方法來實現。呼叫了這個方法後將處於阻塞狀態(等待客戶端發起連線)直到乙個客戶端連線,連線 後,accept返回形如(client,address)的乙個元組,其中client是乙個用於與客戶端通訊的socket,address是客戶端 的形如***.***.***.***:***的位址;2、然後服務端處理客戶端的請求;3、處理完成之後又呼叫1。
關於傳輸資料,socket有兩個方法:send和recv。send使用字串引數傳送資料;recv引數是位元組數,表示一次接受的資料量,如果你不確定一次該接受的資料量的話,最好使用1024。
下面給出乙個最小的伺服器/客戶機的例子:
服務端:
import socket
s = socket.socket()
host = socket.gethostname()
port = 1234
s.bind((host, port))
s.listen(5)
while true:
c, addr = s.accept()
print 'got connection from', addr
c.send('thank you for connecting')
c.close()
客戶端:
import socket
s = socket.socket()
host = socket.gethostname()
port = 1234
s.connect((host, port))
print s.recv(1024)
注意:如果你使用ctrl-c來停止服務端的話,如果再次使用相同的埠可能需要等待一會兒。
二、使用socketserver
socketserver模組簡單化了編寫網路伺服器的工作。
它提供了四個基本的服務類:tcpserver(使用tcp協議)、udpserver(使用資料報)、unixstreamserver、
unixdatagramserver。unixstreamserver和unixdatagramserver用於類unix平台。
這四個類處理請求都使用同步的方法,也就是說,在下乙個請求處理開始之前當前的請求處理必須已完成
。 用socketserver建立乙個伺服器需要四步:
1、通過子類化baserequesthandler類和覆蓋它的handle()方法來建立乙個請求處理器類,用於處理進來
的請求;
3、呼叫服務例項物件的handle_request()或serve_forever()方法去處理請求。
下面使用socketserver用同步的方法寫乙個最簡單的伺服器:
from socketserver import tcpserver, streamrequesthandler
#第一步。其中streamrequesthandler類是baserequesthandler類的子類,它為流socket定義了
#rfile和wfile方法
class handler(streamrequesthandler):
def handle(self):
addr = self.request.getpeername()
print 'got connection from', addr
self.wfile.write('thank you for connecting')
#第二步。其中''代表執行伺服器的主機
server = tcpserver(('', 1234), handler)
#第三步。serve_forever()導致進入迴圈狀態
server.serve_forever()
TCP IP 網路程式設計(五)
select並不是把發生變化的檔案描述符單獨集中到一起,而是通過觀察作為監視物件的fd set函式的變化,因此不能避免對所有監視物件的迴圈語句。而且,監視物件變數會發生變化,在呼叫select函式之前要複製並儲存原有資訊,並在每次呼叫時傳遞新的監視物件資訊。傳遞新的監視物件資訊是資源消耗的主要原因,...
Linux網路程式設計(五)
linux伺服器模型。udp伺服器通常採用迴圈伺服器模型,tcp伺服器通常採用併發伺服器模型 實現思路 伺服器建立偵聽socket,並建立子程序。所有子程序呼叫accept,無連線時將睡眠。有連線到來時所有子程序被喚醒。某乙個子程序接受連線後,其他程序繼續睡眠。乙個預先建立子程序的例子。create...
網路程式設計(五) SIGPIPE
sigpipe訊號產生的原因 簡單來說,就是客戶端程式向伺服器端程式傳送了訊息,然後關閉客戶端,伺服器端返回訊息的時候就會收到核心給的sigpipe訊號。tcp的全雙工通道其實是兩條單工通道,client端呼叫close的時候,雖然本意是關閉兩條通道,但是其實只能關閉它傳送的那一條單工通道,還是可以...