python socket传输视频图片 python使用socket高效传输视频数据帧(连续发送图片)
dxwell6 人气:0想了解python使用socket高效传输视频数据帧(连续发送图片)的相关内容吗,dxwell6在本文为您仔细讲解python socket传输视频图片的相关知识和一些Code实例,欢迎阅读和指正,我们先划重点:python,socket传输图片,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
加载全部内容