python使用socket高效传输视频数据帧(连续发送图片)

作者:dxwell6 时间:2021-04-14 23:17:40 

遇到的问题

网上找了一些代码,都是只能建立一次socket传输一张图片,然后断开重新连重新传。而建立一次socket代价不小,反复建立会非常消耗系统资源,因此尝试自己通过一次socket连续传输多张图片

代码问题记录(需要代码的可以直接文末)

在做的过程中发现了一些问题:

socket在传一张图片时是以二进制流的形式传输,图片的二进制流比较大,一般一次传不完,要传很多次。那么接受者是如何知道什么时候才停止接收这张图片呢?那可以让发送者在发图之前先发一个头信息,告诉接收者这个二进制流有多长,然后接收者通过这个来判断是否传完。

这个问题是最让我致命的,由于发送者先发了一个头信息,使用socket.send()函数,然后发送图片也是要用socket.send()函数,接收端使用的是socket.recv(1024)函数,1024是缓存大。麻烦来了,由于发送者使用连续的两个send,而socket.recv(1024)是有缓存的,他会把这两个信息缓存到一起去,信息头和图片信息全被缓存了!!!这会直接导致代码接收逻辑错误。我的做法是,不能有两个send同时出现,那么我就在send中间加一个recv函数(阻塞函数),也就是发送者每发一个消息,接收者就立马回复一个消息,这样就保证了不会连续send

python使用socket高效传输视频数据帧(连续发送图片) 

代码

由于项目存在两种数据源,一种是可见光,一种是红外,所以我最开始还要制作一个信息头,每次发送的时候要告诉接收者这是什么类型的数据,然后再接收

制作不易,记得给个赞哈!

客户端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://blog.csdn.net/a2352159950/article/details/120869464

标签:python,socket,传输
0
投稿

猜你喜欢

  • CSS3变换入门

    2010-01-30 13:29:00
  • Oracle9i取得建表和索引的DDL语句

    2010-07-20 12:59:00
  • Django分组聚合查询实例分享

    2023-08-07 21:44:16
  • 详解微信小程序「渲染层网络层错误」的解决方法

    2024-04-22 13:01:23
  • Python对列表中的各项进行关联详解

    2023-10-26 20:19:34
  • 用python爬取租房网站信息的代码

    2022-04-30 07:03:38
  • Python 爬虫模拟登陆知乎

    2023-11-28 14:32:08
  • Python Tornado之跨域请求与Options请求方式

    2023-11-24 19:47:08
  • 一条select语句引起的瓶颈问题思考

    2024-01-18 02:40:32
  • Vscode常用快捷键列表、插件安装、console.log详解

    2023-02-11 01:29:04
  • CSS元素类型

    2009-04-27 12:25:00
  • 怎么样才能让层显示在FLASH之上呢

    2008-03-05 13:32:00
  • firefox与ie 的javascript区别

    2010-03-14 11:30:00
  • python实现桌面托盘气泡提示

    2023-05-16 21:27:15
  • 实现web打印的各种方法介绍及实现代码

    2024-04-18 09:40:31
  • Vue.js状态管理之Pinia与Vuex详解

    2024-05-28 15:52:52
  • python 判断矩阵中每行非零个数的方法

    2023-05-27 13:00:34
  • node.js回调函数之阻塞调用与非阻塞调用

    2024-05-05 09:21:26
  • SQL对冗余数据的删除重复记录只保留单条的说明

    2024-01-17 07:24:11
  • 解决Django部署设置Debug=False时xadmin后台管理系统样式丢失

    2022-05-09 00:33:57
  • asp之家 网络编程 m.aspxhome.com