博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
TCP实时图像传输
阅读量:3930 次
发布时间:2019-05-23

本文共 3083 字,大约阅读时间需要 10 分钟。

之前尝试过使用UDP进行图像传输,而UDP协议要求包小于64K,对于较大的图像,需要使用分片压缩的方式进行传输,操作较复杂,同时不能保证图片的每一部分都能够正确传输。详见:,

TCP对于传输的数据大小没有限制,同时TCP在发送失败时还有重传机制,可以保证传输的可靠性,所以本文将使用TCP协议来进行图像的实时传输。

基本流程

TCP连接过程见后面的程序,一般服务端创建一个套接字,绑定本地IP,开启监听,然后客户端也创建一个套接字,连接服务端就可以了,详见后面的代码。直接介绍数据传输流程,如下图:

01流程图

由于TCP是以字节流的形式发送数据的,不能预知数据的大小,所以客户端在发送图像数据之前,需要先发送数据长度等信息。同时为了防止粘包(服务端接收到的数据会先缓存在缓冲区,在接收一次数据后,如果不及时处理,下一次接收到的数据也会送到缓冲区。由于这些数据都是字节流形式的,这样两次接收到的数据就会黏在一起,无法分开),客户端在发送完数据长度信息后,不能马上发送图像数据,需要等待服务端返回的应答信号。客户端接收到应答信号后,就可以开始发送图像字节流数据了。服务端完成图像数据接收后,还要返回给客户端一个应答信号,通知客户端开始下一帧图像的传输

程序实现

与前两篇文章不同,本文使用Python来实现主要功能(因为方便)。

运行环境

  • 软件环境:Python3.8
  • 硬件环境:千兆网口(低分辨率下百兆也行)、i3及以上的CPU

服务端

#-*- coding: UTF-8 -*- import socketimport cv2import numpy as npHOST = ''PORT = 8080ADDRESS = (HOST, PORT)# 创建一个套接字tcpServer = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 绑定本地iptcpServer.bind(ADDRESS)# 开始监听tcpServer.listen(5)while True:    print("等待连接……")    client_socket, client_address = tcpServer.accept()    print("连接成功!")    try:        while True:            # 接收标志数据            data = client_socket.recv(1024)            if data:                # 通知客户端“已收到标志数据,可以发送图像数据”                client_socket.send(b"ok")                # 处理标志数据                flag = data.decode().split(",")                # 图像字节流数据的总长度                total = int(flag[0])                # 接收到的数据计数                cnt = 0                # 存放接收到的数据                img_bytes = b""                while cnt < total:                    # 当接收到的数据少于数据总长度时,则循环接收图像数据,直到接收完毕                    data = client_socket.recv(256000)                    img_bytes += data                    cnt += len(data)                    print("receive:" + str(cnt) + "/" + flag[0])                # 通知客户端“已经接收完毕,可以开始下一帧图像的传输”                client_socket.send(b"ok")                # 解析接收到的字节流数据,并显示图像                img = np.asarray(bytearray(img_bytes), dtype="uint8")                img = cv2.imdecode(img, cv2.IMREAD_COLOR)                cv2.imshow("img", img)                cv2.waitKey(1)            else:                print("已断开!")                break    finally:        client_socket.close()

客户端

#-*- coding: UTF-8 -*- import cv2import timeimport socket# 服务端ip地址HOST = '192.168.0.100'# 服务端端口号PORT = 8080ADDRESS = (HOST, PORT)# 创建一个套接字tcpClient = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 连接远程iptcpClient.connect(ADDRESS)cap = cv2.VideoCapture(0)while True:    # 计时    start = time.perf_counter()    # 读取图像    ref, cv_image = cap.read()    # 压缩图像    img_encode = cv2.imencode('.jpg', cv_image, [cv2.IMWRITE_JPEG_QUALITY, 99])[1]    # 转换为字节流    bytedata = img_encode.tostring()    # 标志数据,包括待发送的字节流长度等数据,用‘,’隔开    flag_data = (str(len(bytedata))).encode() + ",".encode() + " ".encode()    tcpClient.send(flag_data)    # 接收服务端的应答    data = tcpClient.recv(1024)    if ("ok" == data.decode()):        # 服务端已经收到标志数据,开始发送图像字节流数据        tcpClient.send(bytedata)    # 接收服务端的应答    data = tcpClient.recv(1024)    if ("ok" == data.decode()):        # 计算发送完成的延时        print("延时:" + str(int((time.perf_counter() - start) * 1000)) + "ms")

注:如果是Python3.7及以下版本,则将time.perf_counter()改为time.clock()即可

参考

转载地址:http://nmvgn.baihongyu.com/

你可能感兴趣的文章
Volatile-2.不保证原子性
查看>>
剑指 Offer 25. 合并两个排序的链表
查看>>
剑指 Offer 26. 树的子结构
查看>>
剑指 Offer 27. 二叉树的镜像
查看>>
使用WinINet获取网页源代码
查看>>
Ansi、Unicode、UTF-8字符串之间的转换和写入文本文件
查看>>
CentOS yum 源的配置与使用
查看>>
Linux RPM 命令参数使用详解 查看 rpm包依赖性
查看>>
xz压缩命令
查看>>
Mysql各种存储引擎对比总结(常用几种)
查看>>
java为我们已经提供了各种锁,为什么还需要分布式锁?
查看>>
一文带你理解mysql中的分区表和合并表(一个常见知识点)
查看>>
为什么 MongoDB 索引选择B-树,而 Mysql 选择B+树(精干总结)
查看>>
你的钱为什么被转走,这篇文章告诉你答案(CSRF详解)
查看>>
JVM中的一个小知识点:深堆和浅堆的概念
查看>>
HashMap的负载因子初始值为什么是0.75?这篇文章以最通俗的方式告诉你答案
查看>>
详解java中一个面试常问的知识点-阻塞队列
查看>>
除了Thread和Runnable,你还知道第三种创建线程的方式Callable吗
查看>>
java线程面试题集锦(第一版本)
查看>>
记一次java中三元表达式的坑(避免踩坑)
查看>>