標籤:
在開始python網路編程之前,首先要瞭解一下通訊端,通訊端是一種電腦網路資料結構。通訊端有兩種,分別是基於檔案型的和基於網路型的,前者如AF_UNIX,後者如AF_INET、AF_NETLINK。通訊端連接埠就像電話號碼一樣,是通訊身份的唯一標識,合法的連接埠號碼範圍為0到65535,其中,小於1024的連接埠號碼為系統保留連接埠,如果是Unix作業系統,保留的連接埠號碼使用可以通過/etc/services檔案獲得。
通訊端的類型有兩種,連線導向的通訊端與不需連線的通訊端。前者提供了順序的、可靠的、不會重複的資料轉送,而且也不會加上資料邊界,每一個要發送的資訊,可能會被拆成多份,實現這種串連的主要協議就是傳輸控制通訊協定TCP,通訊端類型為SOCK_STREAM,使用IP來尋找網路中的主機,這樣就形成了整個系統。不需連線的通訊端,資料到達的順序、可靠性及資料不重複性無法保證,資料報會保留資料邊界,發送訊息時不會拆成小塊,雖有這麼多缺點,但正是不需連線的,所以不需要承擔維持虛電路串連的負擔,效能更好,實現這種串連的主要協議是使用者資料包通訊協定UDP,通訊端類型為SOCK_DGRAM,也是通過IP來尋找網路中的主機。
python網路編程使用socket模組,建立通訊端用其socket()函數,文法如下:
socket(socket_family, socket_type, protocol = 0)
socket_family可以是AF_UNIX或AF_INET,socket_type可以是SOCK_STREAM或SOCK_DGRAM,protocol一般不寫,預設為0。
當我們建立了通訊端以後,所有的互動都將通過對該通訊端對象的方法調用進行,下面列舉一些通訊端對象的常用函數。
伺服器端——
bind():綁定地址到通訊端。
listen():開始TCP監聽。
accept():被動接受TCP客戶的串連,阻塞式等待串連的到來。
用戶端——
connect():主動初始化TCP伺服器串連。
connect_ex():上一個函數的擴充版本,出錯時返回出錯碼,而不是拋出異常。
公用用途——
recv():接收TCP資料。
send():發送TCP資料。
sendall():完整發送TCP資料。
recvfrom():接收UDP資料。
sendto():發送UDP資料。
getpeername():串連到當前通訊端的遠端的地址。
getsockname():當前通訊端的地址。
getsockopt():返回指定通訊端的參數。
setsockopt():設定指定通訊端的參數。
close():關閉通訊端。
阻塞相關——
setblocking():設定通訊端的阻塞與非阻塞模式。
settimeout():設定阻塞通訊端操作的逾時時間。
gettimetout():得到阻塞通訊端操作的逾時時間。
面向檔案——
fileno():通訊端的檔案描述符。
makefile():建立一個與該通訊端關聯的檔案。
下面是TCP伺服器的虛擬碼——
ss = socket()#建立伺服器通訊端ss.bind()#把地址綁定到通訊端上ss.listen()#監聽串連inf_loop:#伺服器無限迴圈 cs = ss.accept()#接收客戶的串連 comm_loop:#通訊迴圈 cs.recv()/cs.send()#對話,接收與發送 cs.close()#關閉客戶通訊端ss.close()#關閉伺服器通訊端,可選
下面是TCP用戶端的虛擬碼——
cs = socket()#建立客戶通訊端cs.connect()#嘗試串連伺服器comm_loop:#通訊迴圈 cs.send()/cs.recv ()#對話,發送與接收cs.close()#關閉客戶通訊端
下面以一個簡單的例子作為介紹,伺服器、用戶端在同一台機子上,伺服器充當時間戳記的角色,用戶端發送資料後返回一個帶時間的相同資料。
TimeServer.py——
#!/usr/bin/env python from socket import * from time import ctime HOST = ‘‘ # any available PORT = 21567 # unused BUFSIZE = 1024 ADDR = (HOST, PORT) tcpSerSock = socket(AF_INET, SOCK_STREAM) tcpSerSock.bind(ADDR) tcpSerSock.listen(5) # max concurrence access while True: print ‘waiting for connection...‘ tcpCliSock, addr = tcpSerSock.accept() # blocking and passive print ‘...connected from: ‘, addr while True: data = tcpCliSock.recv(BUFSIZE) if not data: break tcpCliSock.send(‘[%s] %s‘ %(ctime(), data) ) tcpCliSock.close() tcpSerSock.close() # optional and never exec
TimeClient.py——
#!/usr/bin/env python from socket import * HOST = ‘localhost‘ # local host PORT = 21567 # the same port as the server BUFSIZE = 1024 ADDR = (HOST, PORT) tc#!/usr/bin/env python from socket import * pCliSock = socket(AF_INET, SOCK_STREAM) tcpCliSock.connect(ADDR) while True: data = raw_input(‘> ‘) if not data: break tcpCliSock.send(data) data = tcpCliSock.recv(BUFSIZE) if not data: break print data tcpCliSock.close()
UDP相對TCP來說比較簡單,因為是不需連線的,所以服務端不需要listen和accept,用戶端也不需要connect。
下面是UDP伺服器的虛擬碼——
ss = socket()ss.bind()#把地址綁定到通訊端上inf_loop:#伺服器無限迴圈 cs.recvfrom()/cs.sendto()#對話,接收與發送ss.close()#關閉伺服器通訊端,可選
下面是UDP用戶端的虛擬碼——
cs = socket()#建立客戶通訊端comm_loop:#通訊迴圈 cs.sendto()/cs.recvfrom ()#對話,發送與接收cs.close()#關閉客戶通訊端
SocketServer模組是一個基於socket模組的進階別的通訊端通訊模組,它支援在新的線程或進程中處理客戶的請求。這個模組是標準庫中一個進階別的模組,用於簡化網路客戶與伺服器的實現,模組中已經實現了一些可供使用的類。下面用SocketServer實現上面的例子,即時間戳記伺服器。
timeSSSer.py——
#!/usr/bin/env python from SocketServer import (TCPServer as TCP, StreamRequestHandler as SRH) from time import ctime HOST = ‘‘ PORT = 21567 ADDR = (HOST, PORT) class MyRequestHandler(SRH): def handler(self): print ‘... connected from:‘, self.client_address self.wfile.write(‘[%s] %s‘) %(ctime(), self.rfile.readline()) tcpServ = TCP(ADDR, MyRequestHandler) print ‘waiting for connection...‘ tcpServ.serve_forever()
timeSSCli.py——
#!/usr/bin/env python from socket import * HOST = ‘localhost‘ PORT = 21567 BUFSIZE = 1024 ADDR = (HOST, PORT) while True: tcpCliSock = socket(AF_INET, SOCK_STREAM) # socket every time tcpCliSock.connect(ADDR) data = raw_input(‘> ‘) if not data: break tcpCliSock.send(‘%s\r\n‘ %data) data = tcpCliSock.recv(BUFSIZE) if not data: break print data.strip() tcpCliSock.close()
其它——
twisted模組是一個完全事件驅動的網路架構,可以用來開發完全異布的網路應用程式和協議,建立一個完整的系統,系統中可以有網路通訊協定、線程、安全認證、即時通訊、資料庫管理、網頁、電子郵件、命令列參數、圖形介面整合等。下面使用twisted模組實現上面例子中同樣的功能。
timeTSSer.py——
#!/usr/bin/env python from twisted.internet import protocol, reactor from time import ctime PORT = 21567 class TSServProtocol(protocol.Protocol): def connectionMade(self): self.clnt = self.transport.getPeer().host print ‘...connected from:‘, self.clnt def dataReceived(self, data): print ‘...received from [%s]\n\t%s‘ %(self.clnt, data) self.transport.write(‘[%s] %s‘ %(ctime(), data)) factory = protocol.Factory() factory.protocol = TSServProtocol print ‘waiting for connection...‘ reactor.listenTCP(PORT, factory) reactor.run()
timeTSCli.py——
#!/usr/bin/env python from twisted.internet import protocol, reactor HOST = ‘localhost‘ PORT = 21567 class TSClntProtocol(protocol.Protocol): def sendData(self): data = raw_input(‘> ‘) if data: print ‘...sending %s...‘ %data self.transport.write(data) else: self.transport.loseConnection() def connectionMade(self): self.sendData() def dataReceived(self, data): print data self.sendData() factory = protocol.ClientFactory() factory.protocol = TSClntProtocol reactor.connectTCP(HOST, PORT, factory) reactor.run()
asyncore/asynchat模組,為能非同步處理客戶請求的網路應用程式提供底層功能。
select模組,在單線程網路伺服器程式中,管理多個通訊端串連。
python網路編程