TCP协议,传输控制协议(Transmission Control Protocol,TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC793定义。
参考链接:
🔗Python struct.pack用法介绍
🔗OpenCV实现图像网络传输的基本步骤
def TCPClient(host,port): # 通信协议函数(客户端)
"""发送文件(也可以发送图片,但是比较慢)"""
time_now = time.strftime("%Y-%m-%d %H:%M:%S")
# 1.创建一个客户端的socket对象:AF_INET表示IPv4地址、SOCK_STREAM表示使用TCP协议进行通信
tcpclient = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
# 2.设置要连接的服务端的ip和端口
tcpclient.connect((host, port))
print('%s 服务器已连接'%time_now)
return tcpclient
except:
print('服务器连接失败,请修改后重新运行!!')
exit(0)
def TCPSever(host,port): # 通信协议函数(服务端)
time_now = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))
# 1.创建一个客户端的socket对象
tcpserver = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # TCP
# 2.绑定端口:
tcpserver.bind((host,port))
print("%s 服务端已开启" % time_now)
return tcpserver
def SendFile(tcpclient, file):
"""发送文件(也可以发送图片,但是比较慢)"""
fhead = struct.pack(b'128sq', bytes(os.path.basename(file), encoding='utf-8'),
os.stat(file).st_size) # 将图片路径和大小打包成一个二进制字符串
tcpclient.send(fhead)
fp = open(file, 'rb') # 打开要传输的文件(二进制只读模式)
while True:
data = fp.read(1024) # 读入图片数据(每次读取1KB)
if not data:
print('{0} send over...'.format(file))
break
tcpclient.send(data) # 以二进制格式发送文件数据============================================>
def ReceiveFile(tcpserver):
"""循环接收文件"""
# 设置监听
tcpserver.listen(5)
while True:
# 3.接收数据:accept()函数会返回一个元组, 元素1为客户端的socket对象,元素2为客户端的地址(ip地址,端口号)
sock, addr = tcpserver.accept()
print("Accept connection from {0}".format(addr)) # 查看发送端的ip和端口
print("-" * 5 + "开始接收" + "-" * 5)
while True:
fileinfo_size = struct.calcsize('128sq')
print(fileinfo_size)
buf = sock.recv(fileinfo_size) # 接收图片名
if buf:
filename, filesize = struct.unpack('128sq', buf) # 解包
recvd_size = 0
save_name = filename.decode().strip('\x00') # 文件名解码
print(f"文件名:{save_name}")
fp = open(save_name, 'wb')
while not recvd_size == filesize:
if filesize - recvd_size > 1024:
data = sock.recv(1024)
recvd_size += len(data)
else:
data = sock.recv(1024)
recvd_size = filesize
fp.write(data) # 写入文件数据
fp.close()
print("-" * 5 + "接收完成" + "-" * 5)
sock.close()
break
def SendImgArray(tcpclient,file):
"""发送图片(OpenCV读取的图像数组)"""
img = cv2.imread(file)
# 图片编码
params = [cv2.IMWRITE_JPEG_QUALITY, 100] # 指定JPEG的图像质量,100(最高质量)
img_encode = cv2.imencode('.jpg', img, params)[1]
data_encode = np.array(img_encode)
data = data_encode.tobytes()
len_data = len(data)
fhead = struct.pack(b'128siiiiq',
bytes(os.path.basename(file), encoding='utf-8'),
1263,627,1459,1073,
len_data) # 将图片路径和大小打包成一个二进制字符串
# 3.发送数据
tcpclient.send(fhead)
tcpclient.send(data) # 发送图片============================================================>
def ReceiveImg(tcpserver):
"""循环接收图片"""
# 设置监听
tcpserver.listen(5)
while True:
# 3.接收数据:accept()函数会返回一个元组, 元素1为客户端的socket对象,元素2为客户端的地址(ip地址,端口号)
sock, addr = tcpserver.accept()
print("Accept connection from {0}".format(addr)) # 查看发送端的ip和端口
print("-" * 5 + "开始接收" + "-" * 5)
while True:
fileinfo_size = struct.calcsize('128siiiiq')
buf = sock.recv(fileinfo_size) # 接收图片名
if buf:
filename,x1,y1,x2,y2,filesize = struct.unpack('128siiiiq', buf) # 解包
save_name = filename.decode().strip('\x00') # 文件名解码
print(f"图片名称:{save_name}")
print(f"目标检测坐标:{x1,y1,x2,y2}") # 附加信息,可以自定义
data = b''
while len(data)<filesize:
data += sock.recv(1024)
img_decode = cv2.imdecode(np.frombuffer(data, dtype=np.uint8), cv2.IMREAD_COLOR)
# 显示图像
cv2.imshow('Image', img_decode)
cv2.waitKey(500) # 显示时长根据传输的速度自定义
# 保存图像
cv2.imwrite(save_name,img_decode)
print("-" * 5 + "接收完成" + "-" * 5)
cv2.destroyAllWindows()
break
def SendFrame(host, port,add=0): # 仅传视频
cap = cv2.VideoCapture(add) # 生成读取摄像头对象
# 定义视频对象输出
# width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) # 获取视频的宽度
# height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 获取视频的高度
# fps = cap.get(cv2.CAP_PROP_FPS) # 获取视频的帧率
# fourcc = int(cap.get(cv2.CAP_PROP_FOURCC)) # 视频的编码
# writer = cv2.VideoWriter("video_result.mp4", fourcc, fps, (width, height))
while cap.isOpened():
tcpclient = TCPClient(host, port)
ret, frame = cap.read() # 读取摄像头画面
hm = int(round(time.time() * 1000))
frame_now = datetime.datetime.fromtimestamp(hm/1000).strftime("%Y%m%d%H%M%S%f")
# 图像压缩
frame = cv2.resize(frame, (192, 108))
# 图像编码
params = [cv2.IMWRITE_JPEG_QUALITY, 100] # ratio:0~100
frame_encode = cv2.imencode('.jpg', frame, params)[1] # 图像编码
frame_encode = np.array(frame_encode)
frame_encode = frame_encode.tobytes()
# 3.发送数据
len_data = len(frame_encode)
fhead = struct.pack(b'128sq',
bytes(frame_now, encoding='utf-8'),
len_data) # 将图片路径和大小打包成一个二进制字符串
# 3.发送数据
tcpclient.send(fhead)
tcpclient.send(frame_encode) # 发送图片============================================================
# 显示画面
cv2.imshow('Map', frame)
key = cv2.waitKey(24)
# writer.write(frame) #视频保存
# 按Q退出
if key == ord('q'):
break
cap.release() # 释放摄像头
cv2.destroyAllWindows() # 释放所有显示图像窗口
def ReceiveFrame(tcpserver):
"""循环接收视频帧"""
# 设置监听
tcpserver.listen(5)
while True:
# 3.接收数据:accept()函数会返回一个元组, 元素1为客户端的socket对象,元素2为客户端的地址(ip地址,端口号)
sock, addr = tcpserver.accept()
print("Accept connection from {0}".format(addr)) # 查看发送端的ip和端口
print("-" * 5 + "开始接收" + "-" * 5)
while True:
fileinfo_size = struct.calcsize('128sq')
buf = sock.recv(fileinfo_size) # 接收图片名
if buf:
filename,filesize = struct.unpack('128sq', buf) # 解包
save_name = filename.decode().strip('\x00') # 文件名解码
print(f"图片名称:{save_name}")
data = b''
while len(data)<filesize:
data += sock.recv(1024)
img_decode = cv2.imdecode(np.frombuffer(data, dtype=np.uint8), cv2.IMREAD_COLOR)
# 显示图像
cv2.imshow('Image', img_decode)
cv2.waitKey(500) # 显示时长根据传输的速度自定义
# 保存图像
# cv2.imwrite(save_name,img_decode)
print("-" * 5 + "接收完成" + "-" * 5)
cv2.destroyAllWindows()
break
完整代码如下:
# -*- coding: utf-8 -*-
"""
2023.12.28
author:alian
function
发送端:车载服务器
1.传输文件
2.传输图片
3.传输视频帧
"""
import os.path
import socket
import cv2
import numpy as np
import time
import struct
import glob
import datetime
def TCPClient(host,port): # 通信协议函数(客户端)
"""发送文件(也可以发送图片,但是比较慢)"""
time_now = time.strftime("%Y-%m-%d %H:%M:%S")
# 1.创建一个客户端的socket对象:AF_INET表示IPv4地址、SOCK_STREAM表示使用TCP协议进行通信
tcpclient = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
# 2.设置要连接的服务端的ip和端口
tcpclient.connect((host, port))
print('%s 服务器已连接'%time_now)
return tcpclient
except:
print('服务器连接失败,请修改后重新运行!!')
exit(0)
def SendFile(tcpclient, file):
"""发送文件(也可以发送图片,但是比较慢)"""
fhead = struct.pack(b'128sq', bytes(os.path.basename(file), encoding='utf-8'),
os.stat(file).st_size) # 将图片路径和大小打包成一个二进制字符串
tcpclient.send(fhead)
fp = open(file, 'rb') # 打开要传输的文件(二进制只读模式)
while True:
data = fp.read(1024) # 读入图片数据(每次读取1KB)
if not data:
print('{0} send over...'.format(file))
break
tcpclient.send(data) # 以二进制格式发送文件数据============================================>
# 4.关闭客户端
tcpclient.close()
def SendImgArray(tcpclient,file):
"""发送图片(OpenCV读取的图像数组)"""
img = cv2.imread(file)
# 图片编码
params = [cv2.IMWRITE_JPEG_QUALITY, 100] # 指定JPEG的图像质量,100(最高质量)
img_encode = cv2.imencode('.jpg', img, params)[1]
data_encode = np.array(img_encode)
data = data_encode.tobytes()
len_data = len(data)
fhead = struct.pack(b'128siiiiq',
bytes(os.path.basename(file), encoding='utf-8'),
1263,627,1459,1073,
len_data) # 将图片路径和大小打包成一个二进制字符串
# 3.发送数据
tcpclient.send(fhead)
tcpclient.send(data) # 发送图片============================================================>
# 4.关闭客户端
tcpclient.close()
def SendFrame(host, port,add=0): # 仅传视频
cap = cv2.VideoCapture(add) # 生成读取摄像头对象
# 定义视频对象输出
# width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) # 获取视频的宽度
# height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 获取视频的高度
# fps = cap.get(cv2.CAP_PROP_FPS) # 获取视频的帧率
# fourcc = int(cap.get(cv2.CAP_PROP_FOURCC)) # 视频的编码
# writer = cv2.VideoWriter("video_result.mp4", fourcc, fps, (width, height))
while cap.isOpened():
tcpclient = TCPClient(host, port)
ret, frame = cap.read() # 读取摄像头画面
hm = int(round(time.time() * 1000))
frame_now = datetime.datetime.fromtimestamp(hm/1000).strftime("%Y%m%d%H%M%S%f")
# 图像压缩
frame = cv2.resize(frame, (192, 108))
# 图像编码
params = [cv2.IMWRITE_JPEG_QUALITY, 100] # ratio:0~100
frame_encode = cv2.imencode('.jpg', frame, params)[1] # 图像编码
frame_encode = np.array(frame_encode)
frame_encode = frame_encode.tobytes()
# 3.发送数据
len_data = len(frame_encode)
fhead = struct.pack(b'128sq',
bytes(frame_now, encoding='utf-8'),
len_data) # 将图片路径和大小打包成一个二进制字符串
# 3.发送数据
tcpclient.send(fhead)
tcpclient.send(frame_encode) # 发送图片============================================================
# 显示画面
cv2.imshow('Map', frame)
key = cv2.waitKey(24)
# writer.write(frame) #视频保存
# 按Q退出
if key == ord('q'):
break
cap.release() # 释放摄像头
cv2.destroyAllWindows() # 释放所有显示图像窗口
if __name__ == "__main__":
file_path = '/media/ll/AI-2/20231225-bjdt/Camera/Camera_1226/results_txt' # 路径
file_list = glob.glob('%s/*'%file_path) # 文件列表
"""
车载ip:20.198.147.136
地面ip:172.16.77.1
alian_ubuntu:192.168.2.42
alian_window:192.168.2.36
"""
host = "192.168.2.36"
port = 6666
for file in file_list:
tcpclient = TCPClient(host,port)
# 3.发送数据
# 3.1 发送文件
SendFile(tcpclient, file)
# 3.2 发送图片
# SendImgArray(tcpclient, file)
# 3.3 发送视频帧(接收端与图片接收端一致)
# SendFrame(host, port, add=0)
#coding:utf-8
"""
2023-12-28
author:alian
function
接收端:地面服务器
1.循环接收文件
2.循环接收图片
3.循环接收视频帧
"""
import socket
import cv2
import numpy as np
import time
import struct
def TCPSever(host,port): # 通信协议函数(服务端)
time_now = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))
# 1.创建一个客户端的socket对象
tcpserver = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # TCP
# 2.绑定端口:
tcpserver.bind((host,port))
print("%s 服务端已开启" % time_now)
return tcpserver
def ReceiveFile(tcpserver):
"""循环接收文件"""
# 设置监听
tcpserver.listen(5)
while True:
# 3.接收数据:accept()函数会返回一个元组, 元素1为客户端的socket对象,元素2为客户端的地址(ip地址,端口号)
sock, addr = tcpserver.accept()
print("Accept connection from {0}".format(addr)) # 查看发送端的ip和端口
print("-" * 5 + "开始接收" + "-" * 5)
while True:
fileinfo_size = struct.calcsize('128sq')
print(fileinfo_size)
buf = sock.recv(fileinfo_size) # 接收图片名
if buf:
filename, filesize = struct.unpack('128sq', buf) # 解包
recvd_size = 0
save_name = filename.decode().strip('\x00') # 文件名解码
print(f"文件名:{save_name}")
fp = open(save_name, 'wb')
while not recvd_size == filesize:
if filesize - recvd_size > 1024:
data = sock.recv(1024)
recvd_size += len(data)
else:
data = sock.recv(1024)
recvd_size = filesize
fp.write(data) # 写入文件数据
fp.close()
print("-" * 5 + "接收完成" + "-" * 5)
sock.close()
break
def ReceiveImg(tcpserver):
"""循环接收图片"""
# 设置监听
tcpserver.listen(5)
while True:
# 3.接收数据:accept()函数会返回一个元组, 元素1为客户端的socket对象,元素2为客户端的地址(ip地址,端口号)
sock, addr = tcpserver.accept()
print("Accept connection from {0}".format(addr)) # 查看发送端的ip和端口
print("-" * 5 + "开始接收" + "-" * 5)
while True:
fileinfo_size = struct.calcsize('128siiiiq')
buf = sock.recv(fileinfo_size) # 接收图片名
if buf:
filename,x1,y1,x2,y2,filesize = struct.unpack('128siiiiq', buf) # 解包
save_name = filename.decode().strip('\x00') # 文件名解码
print(f"图片名称:{save_name}")
print(f"目标检测坐标:{x1,y1,x2,y2}") # 附加信息,可以自定义
data = b''
while len(data)<filesize:
data += sock.recv(1024)
img_decode = cv2.imdecode(np.frombuffer(data, dtype=np.uint8), cv2.IMREAD_COLOR)
# 显示图像
cv2.imshow('Image', img_decode)
cv2.waitKey(500) # 显示时长根据传输的速度自定义
# 保存图像
cv2.imwrite(save_name,img_decode)
print("-" * 5 + "接收完成" + "-" * 5)
cv2.destroyAllWindows()
break
def ReceiveFrame(tcpserver):
"""循环接收图片"""
# 设置监听
tcpserver.listen(5)
while True:
# 3.接收数据:accept()函数会返回一个元组, 元素1为客户端的socket对象,元素2为客户端的地址(ip地址,端口号)
sock, addr = tcpserver.accept()
print("Accept connection from {0}".format(addr)) # 查看发送端的ip和端口
print("-" * 5 + "开始接收" + "-" * 5)
while True:
fileinfo_size = struct.calcsize('128sq')
buf = sock.recv(fileinfo_size) # 接收图片名
if buf:
filename,filesize = struct.unpack('128sq', buf) # 解包
save_name = filename.decode().strip('\x00') # 文件名解码
print(f"图片名称:{save_name}")
data = b''
while len(data)<filesize:
data += sock.recv(1024)
img_decode = cv2.imdecode(np.frombuffer(data, dtype=np.uint8), cv2.IMREAD_COLOR)
# 显示图像
cv2.imshow('Image', img_decode)
cv2.waitKey(500) # 显示时长根据传输的速度自定义
# 保存图像
# cv2.imwrite(save_name,img_decode)
print("-" * 5 + "接收完成" + "-" * 5)
cv2.destroyAllWindows()
break
if __name__=="__main__":
host,port = '192.168.2.36', 6666
tcpserver = TCPSever(host,port)
# 3.接收数据
# 3.1 接收文件函数
ReceiveFile(tcpserver)
# 3.2 接收图片函数
# ReceiveImg(tcpserver)
# 3.3 接收视频帧
# ReceiveFrame(tcpserver)
# 4.关闭服务端
tcpserver.close()