python使用socket高效傳輸視頻數據幀(連續發送圖片)
遇到的問題
網上找瞭一些代碼,都是隻能建立一次socket傳輸一張圖片,然後斷開重新連重新傳。而建立一次socket代價不小,反復建立會非常消耗系統資源,因此嘗試自己通過一次socket連續傳輸多張圖片
代碼問題記錄(需要代碼的可以直接文末)
在做的過程中發現瞭一些問題:
socket在傳一張圖片時是以二進制流的形式傳輸,圖片的二進制流比較大,一般一次傳不完,要傳很多次。那麼接受者是如何知道什麼時候才停止接收這張圖片呢?那可以讓發送者在發圖之前先發一個頭信息,告訴接收者這個二進制流有多長,然後接收者通過這個來判斷是否傳完。
這個問題是最讓我致命的,由於發送者先發瞭一個頭信息,使用socket.send()函數,然後發送圖片也是要用socket.send()函數,接收端使用的是socket.recv(1024)函數,1024是緩存大。麻煩來瞭,由於發送者使用連續的兩個send,而socket.recv(1024)是有緩存的,他會把這兩個信息緩存到一起去,信息頭和圖片信息全被緩存瞭!!!這會直接導致代碼接收邏輯錯誤。我的做法是,不能有兩個send同時出現,那麼我就在send中間加一個recv函數(阻塞函數),也就是發送者每發一個消息,接收者就立馬回復一個消息,這樣就保證瞭不會連續send
代碼
由於項目存在兩種數據源,一種是可見光,一種是紅外,所以我最開始還要制作一個信息頭,每次發送的時候要告訴接收者這是什麼類型的數據,然後再接收
制作不易,記得給個贊哈!
客戶端clien.py
# 服務器的地址 server_address = ('127.0.0.1', 8000) def send(dir_name, data_format, file_name): # 與接收端建立socket通信 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # AF_INET(TCP/IP – IPv4)協議 sock.connect(server_address) # 每次通信都帶一個通信頭,表明數據源的類型(紅外還是可見光),要保存數據幀的文件夾名file_name # 你可以不要數據格式,這裡可以定義成你自己的形式,也算是一種安全機制 sock.send('{}|{}'.format(data_format, file_name).encode()) # 默認編碼 utf-8,發送文件長度和文件名 reply = sock.recv(1024) # 按照文件名排序,0.png,1.png file_list = os.listdir(dir_name) file_list.sort(key=lambda x: int(x[:-4])) if 'ok' == reply.decode(): # 確認一下服務器get到文件長度和文件名數據 i = 0 print(len(file_list)) for file_name in file_list: data = file_deal(os.path.join(dir_name, file_name)) sock.send('{}|{}'.format(len(data), file_name).encode()) sock.recv(1024) go = 0 total = len(data) while go < total: # 發送文件 data_to_send = data[go:go + total//2] sock.send(data_to_send) go += len(data_to_send) sock.recv(1024).decode() i += 1 if i < len(file_list): sock.send(b'continue') sock.send(b'over') sock.close() sys.exit(0) def file_deal(file_path): # 讀取文件的方法 mes = b'' try: file = open(file_path, 'rb') mes = file.read() except: print('error{}'.format(file_path)) else: file.close() return mes
服務端server.py
LOCAL_IP = '127.0.0.1' # 本機測試使用ip,局域網中使用需更換ip PORT = 8000 # 隨意指定一個端口 def server(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # socket.AF_INET 指ipv4 socket.SOCK_STREAM 使用tcp協議 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 設置端口 sock.bind((LOCAL_IP, PORT)) # 綁定端口 sock.listen(3) # 監聽端口 while True: sc, sc_name = sock.accept() # 當有請求到指定端口是 accept()會返回一個新的socket和對方主機的(ip,port) print('收到{}機器請求'.format(sc_name)) info = sc.recv(1024) # 接受客戶端發來的協議頭,區分數據源 # 安全處理:如果不是以這個協議頭開始,認為是非法接入,就直接斷掉。這裡可以自己定義一些安全消息機制 print(info) try: data_format, directory_name = info.decode().split("|") sc.send(b'ok') # 表示收到文件長度和文件名 except: print('協議頭不對,自動斷開連接') sc.close() continue if not os.path.exists(directory_name): os.mkdir(directory_name) # 協議頭正確之後,不斷接收發來的數據幀 while True: head_info = sc.recv(1024) # print(data_info) length, file_name = head_info.decode().split('|') sc.send(b'ok') if length and file_name: print(file_name) newfile = open(os.path.join(directory_name, file_name), 'wb') # 這裡可以使用從客戶端解析出來的文件名 file = b'' total = int(length) get = 0 while get < total: # 接收文件 data = sc.recv(total//2) file += data get = get + len(data) sc.send(b'ok') print('應該接收{},實際接收{}'.format(length, len(file))) if file: print('actually length:{}'.format(len(file))) newfile.write(file[:]) newfile.close() reply = sc.recv(1024) if reply.decode() == "over": break server()
啟動步驟
1.先啟動server.py
2.再啟動client.py
參考文章
https://blog.csdn.net/hfutzhouyonghang/article/details/86624684
到此這篇關於python使用socket高效傳輸視頻數據幀(連續發送圖片)的文章就介紹到這瞭,更多相關python socket傳輸視頻數據幀內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Python 基於TCP 傳輸協議的網絡通信實現方法
- python利用socket實現客戶端和服務端之間進行通信
- Python中的套接字編程是什麼?
- Python實現UDP與TCP通信的示例詳解
- Python制作簡易聊天器,搭建UDP網絡通信模型