1. 程式人生 > >TCP程式設計(一)[Python]

TCP程式設計(一)[Python]

因為課題原因,需要使用socket通訊,以下為自學筆記。

Socket介紹

Socket源自於Unix系統,一切皆檔案,socket其實也就是一種特殊的檔案,所以socket函式就是對其進行的開啟關閉、讀寫等操作。

 參考張巖林大佬的描述,socket模組就是針對伺服器端(Server)和客戶端(Client)進行的【開啟】【讀寫】【關閉】操作,具體流程圖如下所示:

 實戰操作

瞭解了Socket通訊的基本原理以及流程後,開始動手自己編寫客戶端和伺服器端的socket通訊。

客戶端

首先明白什麼事客戶端,在發起TCP連線的時候,通常主動發起連線的便是客戶端(Client),被動響應連線的稱作伺服器端(Server)。比如瀏覽網頁的時候,本機就是客戶端,訪問的網頁便是伺服器端。

下面是一個簡單的基於TCP通訊的Socket連線。以客戶端為例:

#匯入socket庫
import socket

# 建立一個socket:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 建立連線:
s.connect(('www.baidu.com.cn', 80))
cmd = raw_input("Please Input Some Commands")
s.sendall(cmd)

#定義一個buffer來接收資料
buffer = []
#利用while迴圈實現接收所有資料的功能
while True:
    d = s.recv(1024)
    if d:
        #append操作,不斷將d中的資料新增給buffer
        buffer.append(d)
    else:
        break
#將buffer中的元素聯接成一個新的字串
data = b''.join(buffer)
print(data)

#關閉連線
s.close()

首先,匯入socket庫,建立一個socket通訊,其中socket.AF_INET指的是使用IPv4協議,socket.AF_INET6代表IPv6協議(IPV4和IPV6協議的區別自行谷歌) 

然後SOCK_STREAM代表使用流式socket,for TCP,SOCK_DGRAM指的是資料包式socket,for UDP

到這裡,一個正常的socket物件已經建立成功,接下來要建立連線。連線需要伺服器的兩個引數:IP地址和埠號,此處使用了域名直接轉IP地址,而80埠是Web服務的標準埠,通常都會預留一些埠給專用的服務,例如SMTP服務是25埠,FTP服務是21埠,工業協議Modbus/TCP是502埠等等。將兩個引數作為一個元組(tuple)進行輸入。

接下來可以接收伺服器返回的資料,可以呼叫recv(max)函式來指定一次最多接收的位元組數量,可以用一個while迴圈來實現接收返回資料的功能。

最後使用s.close()來關閉連線即可。

伺服器端

通過第一張socket通訊流程圖可以看到,伺服器端實現要比客戶端更加複雜。

首先伺服器端要繫結一個埠並且進行監聽,如果監聽到客戶端傳送過來的請求,那麼伺服器端就與客戶端建立socket連線。

那麼伺服器如何區分到底應該和哪個客戶端進行繫結連線的呢。一個Socket由以下四個引數來唯一確定:

  • 伺服器地址
  • 伺服器埠號
  • 客戶端地址
  • 客戶端埠號

首先,仿照客戶端通訊,先建立一個socket通訊

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

然後繫結需要監聽的地址和埠號, 但是一臺計算機中可能存在多塊網絡卡,可以通過IP地址來區分繫結到哪一張網絡卡,例如0.0.0.0表示繫結到所有網路地址,127.0.0.1表示繫結到本機地址,此時,客戶端必須同時在本機執行才能夠正常連線,外部的計算機是無法進行連線的。

接下來指定繫結的埠號,埠號小於1024指的是Internet標準服務的埠,需要管理員許可權,大於1024的埠則可以任意使用。

# 繫結IP地址和埠號:
s.bind(('127.0.0.1', 8888))

按照流程圖,接下來需要進行監聽操作,呼叫listen()方法可以實現

#監聽埠
#listen()傳入的引數為等待連線的最大數量
s.listen(5)
print('Waiting for connection...')

接來下,依然利用一個while迴圈來實現接收客戶端的連線操作。

while True:
    # 接受一個新連線,並返回新的套接字和IP地址
    conn, addr = s.accept()
    print("Connected to",addr)
    conn.send("Hello World")
    conn.close()

總結

今天先寫到這吧,過兩天寫一下整體的實現,和如何建立新執行緒的方法進行連線。新手寫博,只是做個筆記。

參考連結

https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001432004374523e495f640612f4b08975398796939ec3c000

http://www.cnblogs.com/aylin/p/5572104.html