詳解python tcp編程
網(wǎng)絡(luò)連接與通信是我們學(xué)習(xí)任何編程語言都繞不過的知識點(diǎn)。 Python 也不例外,本文就介紹因特網(wǎng)的核心協(xié)議 TCP ,以及如何用 Python 實(shí)現(xiàn) TCP 的連接與通信。
TCP 協(xié)議
TCP協(xié)議(Transmission Control Protocol, 傳輸控制協(xié)議)是一種面向連接的傳輸層通信協(xié)議,它能提供高可靠性通信,像 HTTP/HTTPS 等網(wǎng)絡(luò)服務(wù)都采用 TCP 協(xié)議通訊。那么網(wǎng)絡(luò)通訊方面都會涉及到 socket 編程,當(dāng)然也包括 TCP 協(xié)議。
Network Socket
我們來看看定義:
Network Socket(網(wǎng)絡(luò)套接字)是計算機(jī)網(wǎng)絡(luò)中進(jìn)程間通信的數(shù)據(jù)流端點(diǎn),廣義上也代表操作系統(tǒng)提供的一種進(jìn)程間通信機(jī)制。
這些計算機(jī)術(shù)語都很學(xué)術(shù),難于理解,每個字都認(rèn)識,加在一起就不認(rèn)識了。我們可以通俗地理解成發(fā)快遞:A 需要給 B 寄快遞,首先需要知道 B 的地址和手機(jī)號碼,那么這個地址就相當(dāng)于 網(wǎng)絡(luò)中的主機(jī) IP 地址,而手機(jī)就相當(dāng)于 主機(jī)的端口號。然后 A 還需要指定哪家快遞公司,是順豐還是中通?這個快遞公司就相當(dāng)于通信的傳輸協(xié)議。
TCP 連接流程
上述快遞的例子中,寄快遞的我們可以叫做客戶端,收快遞的我們叫做服務(wù)器。專業(yè)點(diǎn)就是主動發(fā)起連接的一方叫做客戶端,被動響應(yīng)的一方叫做服務(wù)器。例如,我們在瀏覽器中訪問百度搜索時,我們自己的電腦就是客戶端,瀏覽器會向百度的服務(wù)器發(fā)送連接請求,如果百度的服務(wù)器接受了我們的請求,那么一個 TCP 連接就建立起來了,后面就是百度向我們傳輸搜索結(jié)果了。
我們來看一個流程圖:
TCP服務(wù)器的建立可以歸納這幾步:
- 創(chuàng)建 socket(套接字)
- 綁定 socket 的 IP 地址和端口號
- 監(jiān)聽客戶端的連接請求
- 接受客戶端的連接請求
- 與客戶端對話
- 關(guān)閉連接
TCP客戶端的創(chuàng)建可總結(jié)為這幾步:
- 創(chuàng)建 socket(套接字)
- 連接服務(wù)器 socket
- 與服務(wù)器對話
- 關(guān)閉連接
這里需要注意的是 TCP 客戶端連接到服務(wù)器的 IP 和端口號必須是 TCP 服務(wù)器的 IP 和監(jiān)聽的端口號,服務(wù)器調(diào)用 listen() 開始監(jiān)聽端口,然后調(diào)用 accept() 時刻準(zhǔn)備接受客戶端的連接請求,此時服務(wù)器處于阻塞狀態(tài),直到服務(wù)器監(jiān)聽到客戶端的請求后,接收請求并建立連接為止。
TCP 客戶端
創(chuàng)建 socket 連接,可以這樣做:
# 導(dǎo)入socket庫 import socket # 創(chuàng)建一個socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 建立連接 s.connect(("127.0.0.1", 6000))
創(chuàng)建 socket 時,第一個參數(shù) socket.AF_INET 表示指定使用 IPv4 協(xié)議,如果要使用 IPv6 協(xié)議,就指定為 socket.AF_INET6。SOCK_STREAM 指定使用面向流的 TCP 協(xié)議。然后我們調(diào)用 connect() 方法,傳入 IP 地址(或者域名),指定端口號就可以建立連接了。
接下來我們就可以向服務(wù)器發(fā)送數(shù)據(jù)了:
s.send(b'Hello, Mr Right!')
接收數(shù)據(jù)時,調(diào)用 recv(max) 方法,一次最多接收指定的字節(jié)數(shù),因此,在一個 while 循環(huán)中反復(fù)接收,直到 recv() 返回空數(shù)據(jù),表示接收完畢,退出循環(huán)。
# 接收數(shù)據(jù) buffer = [] while True: # 每次最多接收1k字節(jié) d = s.recv(1024) if d: buffer.append(d) else: break data = b''.join(buffer)
最后,我們需要關(guān)閉連接,很簡單:
s.close()
TCP 服務(wù)器
相比于客戶端,服務(wù)器端稍微復(fù)雜一些,需要先綁定一個 IP 地址和端口號,然后監(jiān)聽客戶端的請求,收到請求后丟到一個線程去處理。
創(chuàng)建 socket 跟客戶端方法一樣:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
接下來需要綁定監(jiān)聽地址和端口:
s.bind(('127.0.0.1', 6000))
然后就可以開始監(jiān)聽端口了,監(jiān)聽時需要傳入一個參數(shù),指定等待連接的最大數(shù)量:
s.listen(5)
接下來就是無限循環(huán)等待客戶端的連接,直到有連接請求過來,就用一個線程去處理:
while True: # 接受一個新連接 sock, addr = s.accept() # 創(chuàng)建新線程來處理TCP連接 t = threading.Thread(target=tcplink, args=(sock, addr)) t.start()
這里為什么需要多線程處理呢?想象一下菜鳥驛站,如果里面只有一個人的話,那么多個人寄件就需要排隊(duì),一個個來;但是如果有多個人的話,那么每個人都可以處理一個寄件請求。
我們來看一下處理客戶端請求的方法:
# 處理tcp連接 def tcplink(conn, addr): print("Accept new connection from %s:%s" % addr) # 向客戶端發(fā)送歡迎消息 conn.send(b"Server: Welcome!\n") while True: conn.send(b"Server: What's your name?") data = conn.recv(1024) # 如果客戶端發(fā)送 exit 過來請求退出,結(jié)束循環(huán) if data == b"exit": conn.send(b"Server: Good bye!\n") break conn.send(b"Server: Hello %s!\n" % data) # 關(guān)閉連接 conn.close() print("Connection from %s:%s is closed" % addr)
例子中,我們先想客戶端發(fā)送歡迎消息,然后詢問客戶端名稱,收到名稱后發(fā)送歡迎消息,直到接收到客戶端的 ‘exit' 命令,退出循環(huán),關(guān)閉連接。
實(shí)例
我們把上面的分步講解代碼合并起來,形成一個可運(yùn)行的實(shí)例。
服務(wù)器端代碼:
import socket import threading import time # 處理tcp連接 def tcplink(conn, addr): print("Accept new connection from %s:%s" % addr) # 向客戶端發(fā)送歡迎消息 conn.send(b"Server: Welcome!\n") while True: conn.send(b"Server: What's your name?") data = conn.recv(1024) # 如果客戶端發(fā)送 exit 過來請求退出,結(jié)束循環(huán) if data == b"exit": conn.send(b"Server: Good bye!\n") break conn.send(b"Server: Hello %s!\n" % data) time.sleep(5) # 關(guān)閉連接 conn.close() print("Connection from %s:%s is closed" % addr) # 創(chuàng)建 socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 監(jiān)聽端口 s.bind(("127.0.0.1", 6000)) # 設(shè)定等待連接的最大數(shù)量為5 s.listen(5) print("Waiting for connection...") # 等待接收連接 while True: # 接受一個新連接 conn, addr = s.accept() # 創(chuàng)建新線程來處理TCP連接 t = threading.Thread(target=tcplink, args=(conn, addr)) t.start()
客戶端代碼:
import socket import time # 創(chuàng)建 socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 建立連接 s.connect(("127.0.0.1", 6000)) # 接收服務(wù)器消息 print(s.recv(1024).decode()) for data in [b'Michael', b'Tracy', b'Sarah']: # 發(fā)送數(shù)據(jù) s.send(data) time.sleep(2) # 打印接收到的數(shù)據(jù) print(s.recv(1024).decode('utf-8')) time.sleep(1) time.sleep(3) # 請求退出 s.send(b'exit') time.sleep(2) print(s.recv(1024).decode('utf-8')) # 關(guān)閉連接 s.close()
注意,在代碼中,我加入了一些休眠(sleep)操作,主要是為了控制臺能夠順利打印出來,不然程序運(yùn)行太快,打印順序和內(nèi)容有可能和預(yù)期不一樣。
先運(yùn)行服務(wù)器端代碼,然后再運(yùn)行客戶端代碼,我們可以看到服務(wù)器端控制臺打印內(nèi)容如下:
# 服務(wù)器端打印消息 Waiting for connection... Accept new connection from 127.0.0.1:53503 Connection from 127.0.0.1:53503 is closed
客戶端控制臺打印內(nèi)容如下:
# 客戶端打印消息 Server: Welcome! Server: What's your name? Server: Hello Michael! Server: What's your name? Server: Hello Tracy! Server: What's your name? Server: Hello Sarah! Server: What's your name? Server: Good bye!
大家可以對照著打印內(nèi)容和代碼,體會一下服務(wù)器端和客戶端通信的原理。
總結(jié)
本文為大家介紹了 TCP 編程的基本原理和如何使用 Python 實(shí)現(xiàn)一個最簡單的 TCP 通信過程。通過介紹和實(shí)例,大家要在腦海中形成一個 TCP 通信的過程,熟悉了這個過程是處理后續(xù)復(fù)雜通信需求的基礎(chǔ)。
以上就是詳解python tcp編程的詳細(xì)內(nèi)容,更多關(guān)于python tcp編程的資料請關(guān)注腳本之家其它相關(guān)文章!
- Python采用socket模擬TCP通訊的實(shí)現(xiàn)方法
- Python使用socket模塊實(shí)現(xiàn)簡單tcp通信
- Python 創(chuàng)建TCP服務(wù)器的方法
- Python Socket TCP雙端聊天功能實(shí)現(xiàn)過程詳解
- python 使用raw socket進(jìn)行TCP SYN掃描實(shí)例
- Python TCPServer 多線程多客戶端通信的實(shí)現(xiàn)
- python基于TCP實(shí)現(xiàn)的文件下載器功能案例
- python3 tcp的粘包現(xiàn)象和解決辦法解析
- 基于python模擬TCP3次握手連接及發(fā)送數(shù)據(jù)
相關(guān)文章
tensorflow如何將one_hot標(biāo)簽和數(shù)字(整數(shù))標(biāo)簽進(jìn)行相互轉(zhuǎn)化
這篇文章主要介紹了tensorflow如何將one_hot標(biāo)簽和數(shù)字(整數(shù))標(biāo)簽進(jìn)行相互轉(zhuǎn)化問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06python構(gòu)建指數(shù)平滑預(yù)測模型示例
今天小編就為大家分享一篇python構(gòu)建指數(shù)平滑預(yù)測模型示例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11Python實(shí)現(xiàn)Pig Latin小游戲?qū)嵗a
這篇文章主要介紹了Python實(shí)現(xiàn)Pig Latin小游戲?qū)嵗a,分享了相關(guān)代碼示例,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下2018-02-02Python3.5內(nèi)置模塊之os模塊、sys模塊、shutil模塊用法實(shí)例分析
這篇文章主要介紹了Python3.5內(nèi)置模塊之os模塊、sys模塊、shutil模塊用法,結(jié)合實(shí)例形式分析了Python os模塊、sys模塊及shutil模塊針對文件、路徑等相關(guān)操作技巧,需要的朋友可以參考下2019-04-04Python虛擬環(huán)境的創(chuàng)建和使用詳解
這篇文章主要給大家介紹了關(guān)于Python虛擬環(huán)境的創(chuàng)建和使用的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09Python如何按單元格讀取復(fù)雜電子表格(Excel)的數(shù)據(jù)
這篇文章主要介紹了Python如何按單元格讀取復(fù)雜電子表格(Excel)的數(shù)據(jù)問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06Python實(shí)現(xiàn)判斷一個字符串是否包含子串的方法總結(jié)
這篇文章主要介紹了Python實(shí)現(xiàn)判斷一個字符串是否包含子串的方法,結(jié)合實(shí)例形式總結(jié)分析了四種比較常用的字符串子串判定方法,需要的朋友可以參考下2017-11-11Python 網(wǎng)絡(luò)編程之TCP客戶端/服務(wù)端功能示例【基于socket套接字】
這篇文章主要介紹了Python 網(wǎng)絡(luò)編程之TCP客戶端/服務(wù)端功能,結(jié)合實(shí)例形式分析了Python使用socket套接字實(shí)現(xiàn)TCP協(xié)議下的客戶端與服務(wù)器端數(shù)據(jù)傳輸操作技巧,需要的朋友可以參考下2019-10-10