想要写一个client用户端和一个server服务器端,实现客户端向服务器端发送图片文件,服务器端进行处理,并返回处理结果
client.py
import socket
from tqdm import tqdm
import os
import time
if __name__ == "__main__":
# 传输数据分隔符,减少连接次数
SEPARATOR = "<SEPARATOR>"
# 服务器信息
host = '127.0.0.1'
port = 5001
# 客户端信息
c_host = '127.0.0.1'
c_port = 5002
# 文件传输的缓存区
BUFFERSIZE = 4096
# 传输文件名,文件路径
path = r"I:\map\twoMethod\figure"
filename = "0061_Martigues_As_Surveyed_2022-Model.png"
# 文件大小
filesize = os.path.getsize(os.path.join(path,filename))
# 接受回复文件存储位置
replyPath = "temp/"
# 创建socket连接
s = socket.socket()
s.bind((c_host,c_port))
# 连接服务器
print(f"服务器连接中{host}:{port}...")
s.connect((host,port))
print("服务器连接成功...")
# 发送的文件名和文件大小,必须encode()
s.send(f"{filename}{SEPARATOR}{filesize}".encode())
# 文件传输
sendProgress = tqdm(range(filesize),f"发送{filename}",unit="B",unit_divisor=1024,unit_scale=True) # 传输单位B,换算关系1024
with open(os.path.join(path,filename),"rb") as f: # 可以自动关闭f,不想f = open()这种需要额外f.close()
for _ in sendProgress:
# 读取文件
bytesData = f.read(BUFFERSIZE)
if not bytesData: # 五读取数据
break
# sendall确保即使网络忙碌的时候,数据仍可以传输
s.sendall(bytesData)
sendProgress.update(len(bytesData)) # 更新进度条
print(f"服务器连接中{host}:{port}...")
print("开始监听服务器端数据...")
s.shutdown(socket.SHUT_WR)
# # connection, address = s.accept()
receivedFlag = False
with open(os.path.join(replyPath,"output.xlsx"),'wb') as f:
while(1):
bytesData = s.recv(BUFFERSIZE)
if bytesData:
print("receive!")
f.write(bytesData)
receivedFlag = True
if (not bytesData) and receivedFlag:
break
# connection.close()
s.close()
client端发送数据到服务器端口之后开始监听服务器端的回复
server.py
import os
from tqdm import tqdm
import socket
import cv2
import detect
from config import config
import time
# 设置服务器地址
SERVER_HOST = config.SERVER_HOST
SERVER_PORT = config.SERVER_PORT
# 设置读写缓冲区
BUFFERSIZE = 4096
# 定义分隔符
SEPARATOR = "<SEPARATOR>"
# 创建Server
s = socket.socket()
s.bind((SERVER_HOST,SERVER_PORT)) # 把IP和PORT绑定
# 设定连接监听数量
s.listen(5)
print(f"服务器端开始监听{SERVER_HOST}:{SERVER_PORT}...")
# 存储地址
savePath = "temp/"
while True:
# 接受客户端连接
connection,address = s.accept()
# 打印客户端IP
print(f"客户端{address}连接")
# 接受客户端信息
received = connection.recv(BUFFERSIZE).decode()
filename,filesize = received.split(SEPARATOR)
filename = os.path.basename(filename) # 如果传过来是路径,那么只提取文件名
filesize = int(filesize) # 传输过来的是字符串转int类型
# 文件的接受处理
receive_timestamp = time.time()
progress = tqdm(range(filesize),f"接受{filename}",unit="B",unit_divisor=1024,unit_scale=True)
with open(os.path.join(savePath,filename),"wb") as f:
for _ in progress:
print("server receive")
# 从客户端读取数据
bytesData = connection.recv(BUFFERSIZE)
# 如果没有数据传输内容终止读取
if not bytesData:
break
# 读取写入
f.write(bytesData)
# 更新进度条
progress.update(len(bytesData))
# 读取刚刚收到的文件
print("处理接收到的图片...")
img = cv2.imread(os.path.join(savePath,filename))
replyBytes = detect.shelfDetect(img) # 回复的文件数据
# 向客户端推送结果
print(f"向客户端{address}回复结果文件{len(replyBytes)}...")
progress1 = tqdm(range(len(replyBytes)),f"回复{filename}的计算结果",unit="B",unit_divisor=1024,unit_scale=True)
for _ in progress1:
print("send")
bytesData = replyBytes[:BUFFERSIZE]
replyBytes = replyBytes[BUFFERSIZE:]
if not bytesData:
break
connection.sendall(bytesData)
progress1.update(len(bytesData))
# 关闭资源
print("推送完毕!")
connection.close() # 先关客户端
# s.close() # 再关服务端
服务器端接受完数据之后,处理数据并将结果以字节的形式推送到client去
这样写完了之后就出现了一个问题
server端卡在了bytesData = connection.recv(BUFFERSIZE)
上网查找这个recv方法是阻塞的,如果收不到数据就会一直卡在那里等待接收,进入不了后面的程序,也就处理不了接收到的图片,client也会一直监听等待回复。
卡在了recieve的过程中,但是实际上这个时候已经完全接受完了数据
所以这里在client 里面加上s.shutdown(socket.SHUT_WR)
意思就是在传完图片之后,把输出通道关闭,那么server端就知道不用再等待recv了
client.py
这样在发完之后client主动关闭了发送端口,server也不会再等待接受了,直接就进入了处理图片后面的程序
client端也能正常接收到数据
刚刚发现tqdm这里也有一些问题
如果直接for _ in progress
的话,filesize=4096会便利4096次,而你每次接受4096字节的话,其实接受一次就可以了,所以第一次recv接收到数据之后,还会接着循环进入recv的方法,所以卡住了,那么这里其实控制接受的次数就可以了
这样的话再client端即便不主动关闭传输通道,for循环也会结束,数据传输完成之后会自动结束循环,不会再recv也不会在等待了
改之后的
client.py
import socket
from tqdm import tqdm
import os
import time
if __name__ == "__main__":
# 传输数据分隔符,减少连接次数
SEPARATOR = "<SEPARATOR>"
# 服务器信息
host = '127.0.0.1'
port = 5001
# 客户端信息
c_host = '127.0.0.1'
c_port = 5002
# 文件传输的缓存区
BUFFERSIZE = 4096
# 传输文件名,文件路径
path = r"I:\map\twoMethod\figure"
filename = "0061_Martigues_As_Surveyed_2022-Model.png"
# 文件大小
filesize = os.path.getsize(os.path.join(path,filename))
# 接受回复文件存储位置
replyPath = "temp/"
# 创建socket连接
s = socket.socket()
s.bind((c_host,c_port))
# 连接服务器
print(f"服务器连接中{host}:{port}...")
s.connect((host,port))
print("服务器连接成功...")
# 发送的文件名和文件大小,必须encode()
s.send(f"{filename}{SEPARATOR}{filesize}".encode())
# 文件传输
sendProgress = tqdm(range(filesize),f"发送{filename}",unit="B",unit_divisor=1024,unit_scale=True) # 传输单位B,换算关系1024
with open(os.path.join(path,filename),"rb") as f: # 可以自动关闭f,不想f = open()这种需要额外f.close()
for _ in sendProgress:
# 读取文件
bytesData = f.read(BUFFERSIZE)
if not bytesData: # 五读取数据
break
# sendall确保即使网络忙碌的时候,数据仍可以传输
s.sendall(bytesData)
sendProgress.update(len(bytesData)) # 更新进度条
print(f"服务器连接中{host}:{port}...")
print("开始监听服务器端数据...")
# s.shutdown(socket.SHUT_WR)
with open(os.path.join(replyPath,"output.xlsx"),'wb') as f:
while(1):
bytesData = s.recv(BUFFERSIZE)
if bytesData:
f.write(bytesData)
receivedFlag = True
if not bytesData:
break
print("接受完毕!")
s.close()
# s.shutdown(socket.SHUT_RDWR)
server.py
import os
from tqdm import tqdm
import socket
import cv2
import detect
from config import config
import time
import math
# 设置服务器地址
SERVER_HOST = config.SERVER_HOST
SERVER_PORT = config.SERVER_PORT
# 设置读写缓冲区
BUFFERSIZE = 4096
# 定义分隔符
SEPARATOR = "<SEPARATOR>"
# 创建Server
s = socket.socket()
s.bind((SERVER_HOST,SERVER_PORT)) # 把IP和PORT绑定
# 设定连接监听数量
s.listen(5)
print(f"服务器端开始监听{SERVER_HOST}:{SERVER_PORT}...")
# 存储地址
savePath = "temp/"
while True:
# 接受客户端连接
connection,address = s.accept()
# 打印客户端IP
print(f"客户端{address}连接")
# 接受客户端信息
received = connection.recv(BUFFERSIZE).decode()
filename,filesize = received.split(SEPARATOR)
filename = os.path.basename(filename) # 如果传过来是路径,那么只提取文件名
filesize = int(filesize) # 传输过来的是字符串转int类型
# 文件的接受处理
receive_timestamp = time.time()
progress = tqdm(range(filesize),f"接受{filename}",unit="B",unit_divisor=1024,unit_scale=True)
with open(os.path.join(savePath,filename),"wb") as f:
for _ in range(math.ceil(filesize/BUFFERSIZE)):
# 从客户端读取数据
bytesData = connection.recv(BUFFERSIZE)
# 如果没有数据传输内容终止读取
if not bytesData:
break
# 读取写入
f.write(bytesData)
# 更新进度条
progress.update(len(bytesData))
# 读取刚刚收到的文件
print("处理接收到的图片...")
img = cv2.imread(os.path.join(savePath,filename))
replyBytes = detect.shelfDetect(img) # 回复的文件数据
# 向客户端推送结果
print(f"向客户端{address}回复结果文件{len(replyBytes)}...")
progress1 = tqdm(range(len(replyBytes)),f"回复{filename}的计算结果",unit="B",unit_divisor=1024,unit_scale=True)
for _ in range(math.ceil(len(replyBytes)/BUFFERSIZE)):
bytesData = replyBytes[:BUFFERSIZE]
replyBytes = replyBytes[BUFFERSIZE:]
if not bytesData:
break
connection.sendall(bytesData)
progress1.update(len(bytesData))
# 关闭资源
print("推送完毕!")
connection.close() # 先关客户端
# s.close() # 再关服务端