iT邦幫忙

1

解決TCP傳輸黏包的問題(以Python為例)

  • 分享至 

  • xImage
  •  

原理和我那篇C#相同
只是因為Python的編碼工具和C#差異挺大的,所以實作細節上不太一樣

Server.py

import socket
import threading
import struct

class Server:
    def __init__(self, port):
        # https://docs.python.org/3.9/library/socket.html
        self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        
        # IP設定0.0.0.0的原因可參考這篇
        # https://superuser.com/questions/949428/whats-the-difference-between-127-0-0-1-and-0-0-0-0
        self.server.bind(('0.0.0.0', port))
        self.server.listen(1) # 傳入的參數代表允許多少個目標連入
        
        # 因為程式會在等待連線中停住,所以需要使用Thread等非同步方式去處理
        self.threadAccept = threading.Thread(target=self.Accept)
        self.threadAccept.start()
        self.FLAG_RECEIVE = False # 用來控制是否要停止接收資料
        
    def Accept(self):
        print('Wait Connect...')
        self.socket, self.address = self.server.accept()
        print(f'Conneted by {self.address}')
        
        self.server.close() # 若不需要再接收其他連線則可以關掉server這個socket物件
        
        # 準備接收資料
        self.FLAG_RECEIVE = True
        self.threadReceive = threading.Thread(target=self.Receive)
        self.threadReceive.start()
        
    def Receive(self):
        while(self.FLAG_RECEIVE):
            # 因為Client端分兩次傳送資料,所以這邊也要分兩次接收
            # unpack詳情可看這篇: https://cloud.tencent.com/developer/article/1406350
            data = self.socket.recv(4) # int是4byte
            msg_len = struct.unpack('i', data)[0] # 解碼後是tuple型態,由於只有單個資料,所以這邊用[0]
            data = self.socket.recv(msg_len)
            msg = struct.unpack(str(msg_len)+'s', data)[0] #'同上面的unpack
            
            print('Receive: ' + msg.decode('utf-8'))
            
    def Close(self):
        self.FLAG_RECEIVE = False
        self.socket.close()

if __name__ == '__main__':
    server = Server(8000)
    input() # 按下Enter結束程式
    server.Close()

Client.py

import socket
import threading
import struct

class Client:
    def __init__(self, ip, port):
        # https://docs.python.org/3.9/library/socket.html
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.connect((ip, port))
        self.FLAG_SEND = True
        self.thread = threading.Thread(target=self.Send)
        self.thread.start()
        
    def Send(self):
        while(self.FLAG_SEND):
            msg = 'Hello Server!!'.encode('utf-8') # string to byte array
            msg_len = int(len(msg)) # 強制轉為int類型,大小是4 byte
            # 分兩次傳送,先傳遞資料數,再傳遞資料
            # pack詳情可看這篇: https://cloud.tencent.com/developer/article/1406350
            packet_data = struct.pack('i', msg_len) # 將資料封裝
            self.socket.send(packet_data)
            packet_data = struct.pack(str(msg_len)+'s', msg) # 將資料封裝
            self.socket.send(packet_data)
            
    def Close(self):
        self.FLAG_SEND = False
        self.socket.close()

if __name__ == '__main__':
    client = Client('127.0.0.1', 8000)
    input() # 按下Enter結束程式
    client.Close()

圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言