遇到的問題
網上找了一些代碼,都是只能建立一次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
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/330448.html
標籤:其他
上一篇:【語意分割】??偷偷驚呆所有人 1?? 語意分割簡介
下一篇:超解析度重建測驗(ESRGAN)
