最近需要模仿项目中的服务器:服务器不间断的给客户端发送图片及其字符串形式的参数,客户端接收这些信息进行处理,再将处理结果返回到服务端。
在网上找了很多socket代码,要么只能发送字符串信息不支持图片传输;要么是客户端给服务器发送图片,因为一般的逻辑是先启动服务端再启动客户端,所以单纯的把发图的主体改成服务端也怪怪的,因为那样只能先启动客户端。
最后还是选择了socket,完工之后并不是很甘心,主要是需要先启动客户端再启动服务端,感觉别扭。【实现】。
不甘心,在一番周折下,终于找到了python的WebSocket
方法(之前只知道Java有WebSocket),代码要比socket
简洁一些,并且允许服务端主动向客户端发送数据,正适合我的需求。虽然这份代码也是只能传输简单的字符串,但我很愿意在上面改。
WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。
socket是比较底层的接口,只能传输bytes格式的数据。但是WebSocket`是应用层协议,可以传输其他格式的数据(其实到底层之后同样要解析成bytes),比如json。但我除去传输图片同时还要传输字符串,用json的话要么打包成一个字典再转化为json,要么发送两个json,感觉会很倒腾,还不如就直接传两个bytes。
numpy图片
和string字符串
转化为bytes字节流
的方法,还是参考上一篇文章。
server.py
import asyncio
import websockets
import cv2
async def echo(websocket, path):
video_path = 'D:/test/ccc/mp4/1.mp4' #视频路径
cap = cv2.VideoCapture(video_path) # 读取视频
fps = cap.get(cv2.CAP_PROP_FPS) # 获取视频的帧率
while True:
k=0
while cap.isOpened():
success, frame = cap.read()
if success:
k += 1
if k % (fps*4) == 0: # 每隔4s发送一帧图片
# 将numpy图片转化为bytes字节流
_, img_encode = cv2.imencode('.jpg', frame)
img_data = img_encode.tobytes()
# 将string字符串转化为bytes字节流
img_name = (str(k)+'.jpg').encode()
# 连续发送消息
await websocket.send(img_data)
await websocket.send(img_name)
print('已成功发送%3d.jpg,睡眠1秒'%k)
await asyncio.sleep(1) # 休眠1秒
cap.release()
if __name__ == '__main__':
start_server = websockets.serve(echo,'127.0.0.1',6666) # 改为你自己的地址
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
client.py
import asyncio
import websockets
import numpy as np
import cv2
import os
async def hello(uri):
async with websockets.connect(uri) as websocket:
os.makedirs('./save',exist_ok=True)
while True:
img_data = await websocket.recv() # 接收消息
img_name = await websocket.recv() # 接收消息
# 将 图片字节码bytes 转换成一维的numpy数组 到缓存中
img_buffer_numpy = np.frombuffer(img_data, dtype=np.uint8)
# 从指定的内存缓存中读取一维numpy数据,并把数据转换(解码)成图像矩阵格式
frame = cv2.imdecode(img_buffer_numpy, 1)
name = img_name.decode()
cv2.imwrite('./save/'+name, frame)
print('已成功接收',name)
if __name__ == '__main__':
asyncio.get_event_loop().run_until_complete(
hello('ws://127.0.0.1:6666')) # 改为你自己的地址
先运行server.py
,再运行client.py
,效果:
关于报错: websockets.exceptions.ConnectionClosedError: code = 1006 (connection closed abnormally [internal]), no reason
解决办法:
在client.py
中的connect
函数中添加参数如下: websockets.connect(uri, ping_interval=None)
在server.py
中的serve
函数中添加同样的参数: websockets.serve(echo,'127.0.0.1',6666, ping_interval=None)