2015/12/14 Python網絡編程,TCP/IP客戶端和服務器初探


一直不是很清楚服務器的定義,對於什么是服務器/客戶端架構也只有一個模糊的感覺。最近開始學習,才明白一些什么服務器和客戶端的關系。

所謂的服務器,就是提供服務的東西,它是一個硬件或者軟件,可以向一個或者多個客戶端提供所需要的服務。它存在的目的就是等待客戶的請求,然后給客戶服務,再接着等待請求。

而客戶端,就來連上一個服務器,提出自己的請求,然后等待獲得反饋。

比如說,打印機就是一個服務器的例子,與之相連的計算機就是客戶端,通過網絡連接打印機后,給它提出服務需求(打印)和傳輸數據(傳輸內容),然后打印機開始工作,或者返回造成服務失敗的原因(比如缺紙或者沒有墨)打印機是服務器端,它是一只等待請求的,它在一直工作,計算機這端是客戶端,它不是一只工作的。

打印機是一個硬件服務器,也有一些軟件服務器,比如說Web服務器,數據庫服務器等等。

-----------------------------------------------------------------------------

那么它們又是怎樣通過網絡連接的呢?客戶端/服務器之間的網絡編程是如何做的?

首先,我們要創建一個通訊的斷電,讓服務器可以“監聽”請求,好比公司的電話,客戶通過電話設備向公司發行請求。

當然一個服務器在有電話之后還得將自己的電話給潛在的客戶,才能得到響應,也就是說,必須得將網址發給客戶才能有用。

對於客戶端來說,同樣也是創建一個通信端點,然后建立到與服務器的連接,客戶就可以提出請求了。

-------------------------------------------------------------------------------------

關於通訊端點,就要介紹一個概念,叫套接字。

我們之前談的“通訊端點”的概念,是一個關於通訊的抽象,而套接字就是一種有這樣能力數據結構了。

就好比我們應用整型浮點型布爾型一樣,套接字也是一種數據結構,我們通過它來訪問網絡。

套接字起源於上世紀七十年代,在加州大學伯克利分校版本上的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地址在網絡屬性里可以找,如圖:

然后用同樣的程序框架就可以實現兩機間的通訊了,最后可以做到如下圖的一個對講機程序:

當然,要做到一個雙方都可以自由發言的聊天工具,卻又不是這么簡單了。需要有新的嘗試了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM