一直不是很清楚服務器的定義,對於什麼是服務器/客戶端架構也只有一個模糊的感受。最近開始學習,才明白一些什麼服務器和客戶端的關係。數據庫
所謂的服務器,就是提供服務的東西,它是一個硬件或者軟件,能夠向一個或者多個客戶端提供所須要的服務。它存在的目的就是等待客戶的請求,而後給客戶服務,再接着等待請求。編程
而客戶端,就來連上一個服務器,提出本身的請求,而後等待得到反饋。服務器
好比說,打印機就是一個服務器的例子,與之相連的計算機就是客戶端,經過網絡鏈接打印機後,給它提出服務需求(打印)和傳輸數據(傳輸內容),而後打印機開始工做,或者返回形成服務失敗的緣由(好比缺紙或者沒有墨)打印機是服務器端,它是一隻等待請求的,它在一直工做,計算機這端是客戶端,它不是一隻工做的。網絡
打印機是一個硬件服務器,也有一些軟件服務器,好比說Web服務器,數據庫服務器等等。數據結構
-----------------------------------------------------------------------------架構
那麼它們又是怎樣經過網絡鏈接的呢?客戶端/服務器之間的網絡編程是如何作的?框架
首先,咱們要建立一個通信的斷電,讓服務器能夠「監聽」請求,比如公司的電話,客戶經過電話設備向公司發行請求。socket
固然一個服務器在有電話以後還得將本身的電話給潛在的客戶,才能獲得響應,也就是說,必須得將網址發給客戶纔能有用。tcp
對於客戶端來講,一樣也是建立一個通訊端點,而後創建到與服務器的鏈接,客戶就能夠提出請求了。函數
-------------------------------------------------------------------------------------
關於通信端點,就要介紹一個概念,叫套接字。
咱們以前談的「通信端點」的概念,是一個關於通信的抽象,而套接字就是一種有這樣能力數據結構了。
就比如咱們應用整型浮點型布爾型同樣,套接字也是一種數據結構,咱們經過它來訪問網絡。
套接字起源於上世紀七十年代,在加州大學伯克利分校版本上的Unix上創立,開始的時候被設計用於在同一臺機器上的多個應用程序通信,也就是進程間通信,有兩種類型,一種基於文件系統,一種基於網絡。
基於文件系統被用於不一樣進程通信是頗有意義的,由於文件系統是不一樣的進程均可以訪問的。而不一樣電腦間,基於網絡的套接字就是必須的了。
我先只考慮基於網絡的套接字,有兩種地址家族,一種是AF_INET,另外一種是AF_NETLINK。在大部分時候,咱們討論的都是有連接的AF_INET套接字。
套接字的地址是有兩部分組成的,一個是主機,一個是端口。
相似於電話網絡的區號和電話號碼的含義。主機肯定了你訪問的機器,也就是一個IP地址,端口是你所訪問的服務器軟件所使用的端口號。一臺機器上能夠有不少個程序都在使用端口,合法的端口號範圍是0~65535.小於1024的端口號是系統保留的端口號。
-------------------------------------------------------------------------------------
同時,還有一個基礎知識是面向鏈接和麪向無鏈接。
套接字有兩種類型,一種是面向鏈接的,通訊前先創建一條鏈接,而後順序的、可靠的、不會重複的數據傳輸,不會有數據邊界。實現這種鏈接的主要協議是傳輸控制協議(TCP),建立TCP套接字要指定套接字類型是SOCK_STREAM.
另外一種是無鏈接套接字,也就是說傳輸數據前先不鏈接,這樣數據傳輸的順序、可靠性、不重複性就不可保證。這種傳輸的主要協議是用戶數據報協議(UDP)。
----------------------------------------------------------------------------------------------
至此,網絡的基礎暫且放下,開始講Python的網絡編程。
Python提供了一個socket模塊,來建立和使用套接字。
socket()模塊函數
socket(socket_family, socket_type, protocol=0)
這個函數能夠用於建立一個套接字對象,分別寫入套接字家族名和套接字類型。
建立了這個套接字對象後,全部的交互均可以經過該對象的方法調用來進行。
具體的方法能夠直接查Python的文檔,我這裏舉例說明一下建立一個TCP服務器的過程:
from socket import * from time import ctime HOST = '' # 主機 PORT = 8002 # 端口號,能夠隨意選擇 BUFSIZ = 1024 ADDR = (HOST, PORT) #主機端口號組成一個套接字地址 tcpSerSock = socket(AF_INET, SOCK_STREAM) #建立一個套接字對象,是AF_INET族的tcp套接字 tcpSerSock.bind(ADDR) #這個函數用於綁定地址到套接字 tcpSerSock.listen(5) # 服務器開始監聽鏈接,參數表示最多容許同時有幾個鏈接進來 while True: print 'waiting for connection...' tcpCliSock, addr = tcpSerSock.accept() #用於等待鏈接的到來 print '...connected from:',addr while True: data = tcpCliSock.recv(BUFSIZ) #用於接收從客戶端發來的數據 參數表明一次最多接受的數據量,這裏爲1k if not data: break tcpCliSock.send('[%s] %s' % ( ctime(), data)) # 將時間戳做爲內容發送給客戶端 tcpCliSock.close() tcpSerSock.close()
運行時,能夠看到服務器開始運行,等待一個客戶端的鏈接,因此此刻咱們須要用客戶端去鏈接這個服務器。
再寫一個簡單的客戶端的程序:
from socket import * HOST = 'localhost' #因爲服務器開設在本身電腦上,因此主機是本地 PORT = 8002 #同一個鏈接端口 BUFSIZ = 1024 ADDR = (HOST, PORT) tcpCliSock = socket(AF_INET, SOCK_STREAM) #一樣的TCP套接字 tcpCliSock.connect(ADDR) # 鏈接相應的地址,初始化TCP服務器的鏈接 while True: data = raw_input('>') if not data: break tcpCliSock.send(data) # 向服務器傳輸數據 data = tcpCliSock.recv(BUFSIZ) # 接受服務器端的數據 if not data: break print data tcpCliSock.close()
至此,你運行客戶端的程序,就能夠驗證程序了。
固然,爲了學習的樂趣,最好不要在本地鏈接,仍是拿兩臺電腦來鏈接比較好,主要是客戶端要知道服務器端的IP地址。
IP地址在網絡屬性裏能夠找,如圖:
而後用一樣的程序框架就能夠實現兩機間的通信了,最後能夠作到以下圖的一個對講機程序:
固然,要作到一個雙方均可以自由發言的聊天工具,卻又不是這麼簡單了。須要有新的嘗試了。