python通过udp传输图片

2023-05-16

首先要了解UDP的工作模式
UDP工作方式
对于服务器,首先绑定IP和端口,本机测试的时候可以使用127.0.0.1是本机的专有IP,端口号 大于1024的是自定义的,所以用大于1024的端口号,然后接收客户端数据,处理,返回
对于客户端,UDP不用建立连接,只管发送不管接收到没有,所以可以直接对服务器的IP地址和端口号发送信息,然后等待应答。

注意传输的数据是二进制流数据,所以要找方法把需要传输的数据编码成二进制码流,传过去之后再解码即可,这里我用到了opencv读取图片成numpy的array格式,然后编码,传输,最后接到之后再解码。

先说一次性传输整个图片,这个思路就是接受的参数设置很大,而且图片比较小的情况,实现比较简单

首先是服务器脚本,实现了接收、显示、应答
udp_sever.py

# -*- coding: utf-8 -*-

import socket
import cv2
import numpy as np

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 绑定端口:
s.bind(('127.0.0.1', 9999))

print('Bind UDP on 9999...')

while True:
    # 接收数据:
    data, addr = s.recvfrom(400000)
    print('Received from %s:%s.' % addr)
    #解码
    nparr = np.fromstring(data, np.uint8)
    #解码成图片numpy
    img_decode = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
    cv2.imshow('result',img_decode)
    cv2.waitKey()
    reply = "get message!!!"
    s.sendto(reply.encode('utf-8'), addr)
    cv2.destroyAllWindows()

客户端脚本,实现了发送图片,接收应答
udp_client.py

# -*- coding: utf-8 -*-
import socket
import cv2
import numpy as np

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

img = cv2.imread('/home/xbw/jupyter_notebook/0.jpg')
img_encode = cv2.imencode('.jpg', img)[1]
data_encode = np.array(img_encode)
data = data_encode.tostring()

# 发送数据:
s.sendto(data, ('127.0.0.1', 9999))
# 接收数据:
print(s.recv(1024).decode('utf-8'))

s.close()

为了方便理解放一下图片转到二进制再转回图片的代码

import numpy as np
import cv2
img = cv2.imread('0.jpg')
img_encode = cv2.imencode('.jpg', img)[1]
data_encode = np.array(img_encode)
str_encode = data_encode.tostring()
#print(str_encode)
nparr = np.fromstring(str_encode, np.uint8)
img_decode = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
cv2.imshow('result',img_decode)
cv2.waitKey()
cv2.destroyAllWindows()

分批传输图片
搞了好久终于知道怎么分批传输图片了,首先要知道需要传的图片需要多长的内存,不然不知道什么时候停止接收,这样就要考虑加一个文件头,告诉服务器要接受多长的码流。
实现思路是,首先客户端要先发送一个文件头,包含了码流的长度,用一个long int型的数,先用struct.pack打包,发过去,然后循环发送图片的码流即可
接着服务器先接到文件头,确认图片码流的长度,然后循环接收确定长度的码流,最后再解码成图片即可
实现代码如下:
首先是客户端脚本
udp_client.py

# -*- coding: utf-8 -*-
import socket
import cv2
import numpy as np
import struct

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#读取图片,编码成二进制 bytes格式
img = cv2.imread('/home/xbw/jupyter_notebook/0.jpg')
img_encode = cv2.imencode('.jpg', img)[1]
data_encode = np.array(img_encode)
data = data_encode.tostring()
#定义文件头,打包成结构体
fhead = struct.pack('l',len(data))
# 发送文件头:
s.sendto(fhead,('127.0.0.1', 9999))
#循环发送图片码流
for i in range(len(data)//1024+1):
    if 1024*(i+1)>len(data):
    	s.sendto(data[1024*i:], ('127.0.0.1', 9999))
    else:
        s.sendto(data[1024*i:1024*(i+1)], ('127.0.0.1', 9999))
# 接收应答数据:
print(s.recv(1024).decode('utf-8'))
#关闭
s.close()

然后是服务器接收
udp_sever.py

# -*- coding: utf-8 -*-

import socket
import cv2
import numpy as np
import struct

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 绑定端口:
s.bind(('127.0.0.1', 9999))

print('Bind UDP on 9999...')

while True:
    # 接收文件头,文件头的长度由calcsize函数确定,注意这里recvfrom是接收UDP消息,recv是接收TCP消息
    fhead_size = struct.calcsize('l')
    buf,addr = s.recvfrom(fhead_size)
    if buf:
    #这里结果是一个元组,所以把值取出来
        data_size = struct.unpack('l',buf)[0]
	#接收图片码流长度的码流
    recvd_size = 0
    data_total = b''
    while not recvd_size == data_size:
        if data_size -recvd_size >1024:
            data,addr = s.recvfrom(1024)
            recvd_size += len(data)
        else:
            data,addr = s.recvfrom(1024)
            recvd_size = data_size  
        data_total += data
#    data, addr = s.recvfrom(400000)
    print('Received')
#    reply = 'Hello, %s!' % data.decode('utf-8')
#    s.sendto(reply.encode('utf-8'), addr)
	#把接到的码流解码成numpy数组,显示图像
    nparr = np.fromstring(data_total, np.uint8)
    img_decode = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
    cv2.imshow('result',img_decode)
    cv2.waitKey()
    #应答
    reply = "get message!!!"
    s.sendto(reply.encode('utf-8'), addr)
    cv2.destroyAllWindows()

------------------------------------------------------------------分割线-------------------------------------------------------------------

上面是基本的实现,经过一番学习我终于掌握了UDP传输的精髓
首先是确定客户端和服务器的运行机制
客户端:先定义一个socket对象,不用绑定,然后指定IP地址和端口发送消息,然后如果用了recvfrom就会一直阻塞等待应答(这个很有用,作用就是保证对方确实收到,再发新的消息,不用在考虑发送频率的问题了),前面加一个while True就可以循环发送了,如果涉及到很大的消息,可以拆分发送,技巧是先发送一个文件头高速服务器要发的内容有多大(文件头这里建议使用stuct库,看前面例程),然后随后发送文件内容,保证要循环发送,因为每次发送,对面就当发了一次,假如发了2048字节的内容,对面设置的每次收1024,那么剩下的1024就被丢掉了,而不是等待下次继续接收。还有就是发送的是二进制的码流,目前我用到的转换成码流的方法有:图片用opencv,先imencode 转成二进制,然后再转成numpy,然后再tostring。文件头这种,需要确切知道占多大内存,使得服务器好接收的,用了stuct库,里面的pack,unpack,calcsize三个函数非常好用,发送的时候把数据pack一下就能发送了。列表、字典等等,作为文件内容,用到了json,有点万能,先json.dumps转换成json类型,然后再encode编码成二进制即可拿去发送了。

服务器:先定义一个socket对象,绑定IP地址和端口,让客户端可以找到,然后等待接收消息,收到消息之后处理消息,应答,配合客户端的recvfrom,保证接收频率一致,服务器为了保证始终接收消息,一定会有一个while True,接收到的消息是二进制码流,因此要进行解码。针对上面讲的编码方式解码,其实就是编码方式的反向操作:图片,用opencv解码,先是np.fromstring,然后再cv2.imdecode(data, cv2.IMREAD_COLOR)。对于接收文件头,这里有点技巧,用struct.calcsize确定文件头长度,然后只接收这个长度的码流,再unpack出来即可,这里unpack是个元组。对于json,解码就是先decode,再json.loads即可,是上面编码的反向操作。

然后再高端一点的操作,同一个脚本多进程工作,这就要用到了threading.Thread创建多个进程,思路就是新建多个服务器,然后分配给不同的进程,他们的IP地址可以一样,端口号不一样就行,然后就可以在同一个脚本里并行工作了,这里不同于TCP,因为UDP不需要建立连接

然后附上我实现的源码,服务器脚本里有两个进程,一个接收客户端1的图片,另一个接收客户端2的列表
服务器
udp_server.py

# -*- coding: utf-8 -*-
import socket
import cv2
import numpy as np
import struct
import threading
import json
#设置IP地址、两个服务器端口号
dest_ip = '127.0.0.1'
img_port = 9999
msg_port = 6666

#服务器1的处理、应答函数,接收图片、显示、应答
def receive_img(rec_img):
    while True:
        # 接收数据:
        fhead_size = struct.calcsize('l')
        buf,addr = rec_img.recvfrom(fhead_size)
        if buf:
            data_size = struct.unpack('l',buf)[0]
            print(data_size)
        recvd_size = 0
        data_total = b''
        while not recvd_size == data_size:
            if data_size -recvd_size >1024:
                data,addr = rec_img.recvfrom(1024)
                recvd_size += len(data)
            else:
                data,addr = rec_img.recvfrom(1024)
                recvd_size = data_size  
            data_total += data
#       data, addr = rec_img.recvfrom(400000)
        print('Received')
#       reply = 'Hello, %s!' % data.decode('utf-8')
#       rec_img.sendto(reply.encode('utf-8'), addr)

        nparr = np.fromstring(data_total, np.uint8)
        img_decode = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
        cv2.imshow('result',img_decode)
        cv2.waitKey(100)
        reply = "get message!!!"
        rec_img.sendto(reply.encode('utf-8'), addr)
#        cv2.destroyAllWindows()

#服务器2函数,接收消息、输出、应答
def receive_msg(rec_msg):
    while True:
        msg_data ,msg_addr = rec_msg.recvfrom(1024)
        msg_str = msg_data.decode('utf-8')
        msg = json.loads(msg_str)
        print(msg)
        reply = 'get the msg'
        rec_msg.sendto(reply.encode('utf-8'),msg_addr)
    rec_msg.close()

#主函数 创建服务器、绑定端口、创建运行两个进程、调用上面两个函数
def main():
    #创建套接字
    rec_img = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    rec_msg = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    #绑定本地地址端口
    rec_img.bind((dest_ip, img_port))
    rec_msg.bind((dest_ip, msg_port))
    #创建进程
    t_recimg = threading.Thread(target=receive_img, args=(rec_img,))
    t_recmsg = threading.Thread(target=receive_msg, args=(rec_msg,))
    #开始进程
    t_recimg.start()
    t_recmsg.start()
    print('程序正常运行!!!')
    


if __name__ == '__main__':
    main()

客户端1
udp_client_1.py

# -*- coding: utf-8 -*-
import socket
import cv2
import numpy as np
import struct

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
cap = cv2.VideoCapture(0)
#cap.set(3,320)
#cap.set(4,240)
while True:
    
    if cap.isOpened():
        flag, img = cap.read()
#        img = cv2.imread('/home/xbw/jupyter_notebook/0.jpg')
        img_encode = cv2.imencode('.jpg', img)[1]
        data_encode = np.array(img_encode)
        data = data_encode.tostring()
        #定义文件头
        fhead = struct.pack('l',len(data))
        # 发送文件头、数据:
        s.sendto(fhead,('127.0.0.1', 9999))
        for i in range(len(data)//1024+1):
            if 1024*(i+1)>len(data):
    	        s.sendto(data[1024*i:], ('127.0.0.1', 9999))
            else:
                s.sendto(data[1024*i:1024*(i+1)], ('127.0.0.1', 9999))
        # 接收应答:
        cv2.waitKey(1)
        print(s.recv(1024).decode('utf-8'))

s.close()

客户端2
udp_client_2.py

import socket
import cv2
import numpy as np
import struct
import json
import time
#定义套接字
send_msg = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#设置目标IP地址、端口号
target_ip = '127.0.0.1'
target_port = 6666
#发送数据,等待应答
while True:
    data = [0,0,0,1]
    data_str = json.dumps(data)
    send_msg.sendto(data_str.encode(),(target_ip,target_port))
    time.sleep(0.01)
    print(send_msg.recv(1024).decode('utf-8'))
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

python通过udp传输图片 的相关文章

  • Python setuptools:如何在 setup.py 中添加私有存储库 (gitlab)?

    我上传了 2 个包 它们位于我的 gitlab 存储库中 如果我想使用 pip 将它们安装在我的系统中 这很容易 因为 gitlab 可以帮助您 https docs gitlab com ee user packages pypi rep
  • Python有条件求解时滞微分方程

    我在用dde23 of pydelay包来求解延迟微分方程 我的问题 如何有条件地编写方程 例如目标方程有两个选项 when x gt 1 dx dt 0 25 x t tau 1 0 pow x t tau 10 0 0 1 x othe
  • boto3 资源(例如 DynamoDB.Table)的类型注释

    The boto3库提供了几种返回资源的工厂方法 例如 dynamo boto3 resource dynamodb Table os environ DYNAMODB TABLE 我想注释这些资源 以便我可以获得更好的类型检查和完成 但我
  • Python在postgresql表中查找带有单引号符号的字符串

    我需要从 psql 表中查找包含多个单引号的字符串 我当前的解决方案是将单引号替换为双单引号 如下所示 sql query f SELECT exists SELECT 1 FROM table name WHERE my column m
  • 如何在 PyCharm 4.5.2 中使用 PyPy 作为标准/默认解释器?

    如何在 PyCharm 4 5 2 中使用 PyPy 作为标准 默认解释器 一切都在 Ubunutu 14 10 下运行 并且 pypy 已经安装 您可以在项目的设置下进行配置 这个官方文档直接涵盖了 https www jetbrains
  • 了解 Python 中的酸洗

    我最近接到一项作业 需要以腌制形式放置一本字典 其中每个键引用一个列表 唯一的问题是我不知道腌制形式是什么 谁能给我指出一些好的资源的正确方向来帮助我学习这个概念 pickle 模块实现了一个基本但强大的算法 用于序列化和反序列化 Pyth
  • 更改 Altair 中的构面标题位置?

    如何将方面标题 在本例中为年份 移动到每个图的上方 默认值似乎位于图表的一侧 这可以轻易改变吗 import altair as alt from vega datasets import data df data seattle weat
  • 可以用 Django 制作移动应用程序吗?

    我想知道我是否可以在我的网站上使用 Django 代码 并以某种方式在移动应用程序 Flutter 等框架中使用它 那么是否可以使用我现在拥有的 Django 后端并在移动应用程序中使用它 所以就像models views etc 是的 有
  • python 中的 Johansen 协整检验

    我找不到任何有关在处理统计和时间序列分析 pandas 和 statsmodel 的 Python 模块中执行 Johansen 协整检验的功能的参考 有谁知道是否有一些代码可以执行时间序列之间的协整测试 现在 这已在 Python 的 s
  • Apache Spark 中的高效字符串匹配

    我使用 OCR 工具从屏幕截图中提取文本 每个大约 1 5 句话 然而 当手动验证提取的文本时 我注意到时不时会出现一些错误 鉴于文本 你好 我真的很喜欢 Spark 我注意到 1 像 I 和 l 这样的字母被 替换 2 表情符号未被正确提
  • 如何使用 Django 项目设置 SQLite?

    我已阅读 Django 文档 仅供参考 https docs djangoproject com en 1 3 intro tutorial01 https docs djangoproject com en 1 3 intro tutor
  • 乘以行并按单元格值附加到数据框

    考虑以下数据框 df pd DataFrame X a b c d Y a b d e Z a b c d 1 2 1 3 df 我想在 列中附加数字大于 1 的行 并在该行中的数字减 1 df 最好应该 然后看起来像这样 或者它可能看起来
  • 如何将回溯/sys.exc_info() 值保存在变量中?

    我想将错误名称和回溯详细信息保存到变量中 这是我的尝试 import sys try try print x except Exception ex raise NameError except Exception er print 0 s
  • 是否可以将 pd.Series 分配给无序 pd.DataFrame 中的列而不映射到索引(即不重新排序值)?

    在 Pandas 中创建或分配新列时 我发现了一些意外的行为 当我对 pd DataFrame 进行过滤或排序 从而混合索引 然后从 pd Series 创建新列时 Pandas 会重新排序该系列以映射到 DataFrame 索引 例如 d
  • 对数据帧的每 2 小时数据进行 Groupby

    我有一个数据框 Time T201FN1ST2010 T201FN1VT2010 1791 2017 12 26 00 00 00 854 69 0 87 1792 2017 12 26 00 20 00 855 76 0 87 1793
  • 处理大文件的最快方法?

    我有多个 3 GB 制表符分隔文件 每个文件中有 2000 万行 所有行都必须独立处理 任何两行之间没有关系 我的问题是 什么会更快 逐行阅读 with open as infile for line in infile 将文件分块读入内存
  • 在 virtualenvwrapper 中激活环境

    我安装了virtualenv and virtualenvwrapper用这个命令我创建了一个环境 mkvirtualenv cv 它有效 创建后我就处于新环境中 现在我重新启动了我的电脑 我想activate又是那个环境 但是怎么样 我使
  • 如何在 robobrowser-python 中发出 POST 请求

    http robobrowser readthedocs org en latest api html http robobrowser readthedocs org en latest api html 我正在尝试使用 APIbrows
  • python sklearn中的fit方法

    我问自己关于 sklearn 中拟合方法的各种问题 问题1 当我这样做时 from sklearn decomposition import TruncatedSVD model TruncatedSVD svd 1 model fit X
  • 缓存 Flask-登录 user_loader

    我有这个 login manager user loader def load user id None return User query get id 在我引入 Flask Principal 之前它运行得很好 identity loa

随机推荐

  • PHP代码的底层是什么?底层原理是什么?

    PHP代码的底层是由计算机可执行的机器码 xff08 二进制指令 xff09 组成 底层原理是将PHP代码经过编译和解释执行的过程转化为机器码 底层原理可以分为以下几个步骤 xff1a 词法分析 xff08 Lexical Analysis
  • Jetson Xavier NX 的SD卡系统镜像制作

    Jetson Xavier NX 的SD卡系统镜像制作 一 SD卡系统查看二 系统镜像制作三 系统镜像烧录 一 SD卡系统查看 现有的SD卡的内存为128G xff0c 其中64G内存并未分配 span class token commen
  • 嵌入式Linux下使用crond服务

    参考 xff1a https www linuxidc com Linux 2014 02 97369 htm http www linuxidc com Linux 2014 02 97360 htm https blog csdn ne
  • 关于Flexsns Sky 卡80%,以及乱码的解决问题

    一直被 flexsns sky 这个应用折磨好久了 xff0c 刚开始的时候安装成功 但是打开界面一直卡在80 那里 xff0c ucenter 里面的设置也是对的 官网也是挂的 xff01 于是百思不得解 接下来 我来说说我的解决办法把
  • Ubuntu18.04运行ORB-SLAM3(Demo+本地Realsense D415运行)

    ORB SLAM3论文地址 xff1a https arxiv org abs 2007 11898 代码地址 xff1a https github com UZ SLAMLab ORB SLAM3 一 安装库 根据ORB SLAM3源代码
  • ROS中的坐标与坐标系转换

    ROS中的TF 官网建议新工作直接使用tf2 xff0c 因为它有一个更清洁的界面 xff0c 和更好的使用体验 xff08 自ROS Hydro以来 xff0c tf第一代已被 弃用 xff0c 转而支持tf2 xff09 TF介绍 TF
  • 激光雷达与相机融合(二)-----基于openCV的YOLO目标检测

    代码解析 1 加载模型 span class token comment load image from file span cv span class token operator span Mat img span class toke
  • 线程优先权Thread Priority概念总结

    全文参考 WIN32多线程设计 一书 为什么会有线程优先权 xff1a 为什么CPU处理线程时会按优先级执行 xff1f 想象在忙碌的一天中 xff0c 有很多事情待做但时间又不够 xff0c 其中有很多紧急的事情 比如当晚的英语在线测试
  • 将ros cv_bridge关联到自己安装的Opencv版本

    有时候需要同时使用较高版本的openCV 但一般默认安装的ros系统的cv bridge包关联的Opencv版本都较低 xff0c 这时候就需要将cv bridge关联到自己安装的高版本OpenCV 成功方法为第三条 xff0c 前两条为遇
  • chmod +x 与chmod 777的区别

    chmod 43 x 是将文件状态改为可执行 xff0c 而chmod 777 是改变文件读写权限 在linux中使用man命令查看chmod的大纲我们可以得出以下有用的信息 xff1a chmod OPTION MODE MODE FIL
  • WIndowsServer2012 DHCP服务器配置

    DHCP服务器配置 WIndowsServer2012 DHCP服务器配置服务器配置保留IP设置作用域选项 客户机设置 WIndowsServer2012 DHCP服务器配置 服务器配置 1 首先打开服务器管理器 xff0c 点击工具 xf
  • JavaScript设计模式:四、发布订阅模式

    JavaScript设计模式 xff1a 四 发布订阅模式 文章目录 JavaScript设计模式 xff1a 四 发布订阅模式一 概述1 观察者模式2 发布订阅模式3 观察者模式是不是发布订阅模式 一 概述 观察者模式 xff1a 观察者
  • FreeRTOS教程——二值信号量(四)

    二值信号量 信号量简介 目的 xff1a 共享资源访问 与任务同步 信号量类型 xff1a 二值信号量 计数型信号量 互斥信号量 递归互斥信号量 本质上是一种只包含一个项数的队列 二值信号量 0 和 1 xff0c 一种内核机制 内核同步
  • Bug:Warning: [antd: ***] overlay is deprecated. Please use menu instead.以及解决方案

    Ant Design Pro umi4Bug记录 xff1a Bug xff1a Warning antd overlay is deprecated Please use menu instead 解决方案 xff1a yarn add
  • 前端初学者的Ant Design Pro V6总结(上)

    前端初学者的Ant Design Pro V6总结 xff08 上 xff09 一 UI组件开发流程 61 gt 通用 xff08 异步 xff09 函数useEmotionCss 定义CSSuseModel获取全局状态useCallbac
  • 关于C语言在VS2017上开头格式

    span class token macro property span class token directive keyword include span span class token string lt stdio h gt sp
  • Java中Long和long的区别

    Java中Long和long的区别 Java的数据类型分为两种 xff1a 1 基本类型 xff1a byte 8 short 16 int 32 long 64 float 32 double 64 char 16 boolean 1 2
  • Windows 10 下如何彻底关闭 Hyper-V 服务

    CMD运行bcdedit set hypervisorlaunchtype off 恢复使用 xff1a bcdedit set hypervisorlaunchtype auto
  • 从百度运维实践谈“基于机器学习的智能运维”

    清华大学计算机系副教授裴丹于运维自动化专场发表了题为 基于机器学习的智能运维 的演讲 xff0c 上篇参看 科研角度谈 如何实现基于机器学习的智能运维 文章 xff0c 此为下篇 从百度运维实践谈基于机器学习的智能运维 以下为演讲实录 xf
  • python通过udp传输图片

    首先要了解UDP的工作模式 对于服务器 xff0c 首先绑定IP和端口 xff0c 本机测试的时候可以使用127 0 0 1是本机的专有IP xff0c 端口号 大于1024的是自定义的 xff0c 所以用大于1024的端口号 xff0c