基于TCP的Socket通讯
基于 TCP 的 Socket 通訊
最近要實現(xiàn)兩個機器之間基于 TCP 的 socket 通訊(個人使用 Python 實現(xiàn)),嘗試了官方的 demo 代碼后總是被拒絕連接,仔細研究了一下并成功建立兩臺局域網(wǎng)內(nèi)機器之間的通訊,通過兩次請求的方式解決了粘包問題。
通訊建立
在 Python 語言中要實現(xiàn) socket 通訊需要使用內(nèi)置的 socket 包來實現(xiàn),具體使用可以參考官方文檔。
一般,通過下述代碼建立一個 socket 通訊,其中第一個參數(shù)表示使用 ipv4 地址,第二個參數(shù)表示使用 TCP 協(xié)議族,該段調(diào)用會創(chuàng)建一個 Socket 對象,后續(xù)的綁定、連接監(jiān)聽都是基于這個 Socket 對象的。
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)服務(wù)端配置
首先,需要在服務(wù)端開啟通訊監(jiān)聽,等待連接,這里為了演示方便,服務(wù)端返回的信息固定一個字符串。
import socket import TCP_utils# socket.AF_INET使用ipv4協(xié)議族 # socket.SOCK_STREAM使用tcp通訊 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 綁定端口和地址 addr = ("172.18.129.245", 8990) # 改為自己的服務(wù)器ip或者本地環(huán)回 sock.bind(addr) # 監(jiān)聽接入訪問的socket sock.listen(10) while True:print("server is waiting")# 接收消息conn, addr = sock.accept() # 接受客戶端連接data_head = TCP_utils.parse_header(conn)data_len = data_head['data_len']data = conn.recv(data_len)print("服務(wù)端收到消息:{}".format(data.decode("utf-8")))# 發(fā)送反饋msg = 'finish connect'head_len, head_bytes = TCP_utils.create_header('server', msg)conn.send(head_len)conn.send(head_bytes)conn.sendall(msg.encode('utf-8'))conn.close()客戶端配置
開啟服務(wù)端的 socket 監(jiān)聽后就可以與其建立會話了,具體代碼如下。
import socket import TCP_utils# 發(fā)送內(nèi)容到服務(wù)器 while True:sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)addr = ("192.168.43.27", 8990)sock.connect(addr)msg = input("發(fā)送消息:")head_len, head_info = TCP_utils.create_header("client1", msg)sock.send(head_len)sock.send(head_info)sock.sendall(msg.encode("utf-8"))# 接受反饋data_head = TCP_utils.parse_header(sock)data_len = data_head['data_len']data = sock.recv(data_len)print('收到消息', data.decode("utf-8"))# 關(guān)閉鏈接通路sock.close()粘包問題
該問題指的是是客戶端和服務(wù)端進行數(shù)據(jù)傳輸時,接收的一方不知道消息之間的界限(即不能準確判斷不一次性提取多少字節(jié)的數(shù)據(jù))。該問題本質(zhì)上是由于 TCP 協(xié)議本身的缺陷,為了提高效率,TCP 發(fā)送消息時必須等到發(fā)送方收集到足夠多的消息,若每次信息都很少會合成一個 TCP 段進行發(fā)送。
該問題解決也不難,先發(fā)送一個報文頭部信息來指明后面的數(shù)據(jù)的字節(jié)數(shù),該頭部信息包含了發(fā)送方 id 和數(shù)據(jù)段長度(字節(jié)數(shù)),接收方通過數(shù)據(jù)段長度接受指定字節(jié)數(shù)信息。為了控制發(fā)送的成功,將頭部信息通過 struct 模塊的打包方法壓縮為固定 4 字節(jié)。
具體的解析和封裝頭部信息的代碼封裝為 TCP_utils 模塊,代碼如下。
import struct import jsondef create_header(id, data):"""客戶端編號:param id::param data::return:"""data_len = len(data)head_info = {'id': id, 'data_length': data_len}head_json = json.dumps(head_info)head_bytes = head_json.encode('utf-8')head_bytes_len = len(head_bytes)head_length = struct.pack('i', head_bytes_len)return head_length, head_bytesdef parse_header(conn):"""建立的連接:param conn::return:"""head_info = conn.recv(4)head_length = struct.unpack('i', head_info)[0] # 元組格式data_head = conn.recv(head_length).decode('utf-8')data_head = json.loads(data_head)return data_head效果演示
開啟服務(wù)端監(jiān)聽,隨后,通過客戶端建立一個連接 ,進行會話,演示如下圖。
超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術(shù)人生總結(jié)
以上是生活随笔為你收集整理的基于TCP的Socket通讯的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Ubuntu循环登录
- 下一篇: PIP更换国内源