当前位置: 首页 > news >正文

【Python】基于socket函数的TCP通信

基于socket函数的TCP通信

  • 1 引言
    • 1.1 通信协议函数(客户端)
    • 1.2 通信协议函数(服务端)
  • 2 传输文件(以txt文件为例)
    • 2.1 发送端(客户端)
    • 2.2 接受端(服务端)
  • 3 传输图片(基于OpenCV)
    • 3.1 发送端(客户端)
    • 3.2 接受端(服务端)
  • 4 传输视频帧(以默认摄像头为例)
    • 4.1 发送端
    • 4.2 接收端
  • 5 应用实例
    • 5.1 客户端
    • 5.2 服务端

1 引言

TCP协议,传输控制协议(Transmission Control Protocol,TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC793定义。
参考链接:
🔗Python struct.pack用法介绍
🔗OpenCV实现图像网络传输的基本步骤

1.1 通信协议函数(客户端)

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 tcpclientexcept:print('服务器连接失败,请修改后重新运行!!')exit(0)

1.2 通信协议函数(服务端)

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

2 传输文件(以txt文件为例)

2.1 发送端(客户端)

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))breaktcpclient.send(data)  # 以二进制格式发送文件数据============================================>

2.2 接受端(服务端)

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 = 0save_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 = filesizefp.write(data)  # 写入文件数据fp.close()print("-" * 5 + "接收完成" + "-" * 5)sock.close()break

3 传输图片(基于OpenCV)

3.1 发送端(客户端)

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)  # 发送图片============================================================>

3.2 接受端(服务端)

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

4 传输视频帧(以默认摄像头为例)

4.1 发送端

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~100frame_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'):breakcap.release()  # 释放摄像头cv2.destroyAllWindows()  # 释放所有显示图像窗口

4.2 接收端

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

5 应用实例

完整代码如下:

5.1 客户端

# -*- 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 datetimedef 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 tcpclientexcept: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))breaktcpclient.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~100frame_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'):breakcap.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.1alian_ubuntu:192.168.2.42alian_window:192.168.2.36"""host = "192.168.2.36"port = 6666for 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)

5.2 服务端

#coding:utf-8
"""
2023-12-28
author:alian
function
接收端:地面服务器
1.循环接收文件
2.循环接收图片
3.循环接收视频帧
"""
import socket
import cv2
import numpy as np
import time
import structdef 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 tcpserverdef 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 = 0save_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 = filesizefp.write(data)  # 写入文件数据fp.close()print("-" * 5 + "接收完成" + "-" * 5)sock.close()breakdef 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()breakdef 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()breakif __name__=="__main__":host,port = '192.168.2.36', 6666tcpserver = TCPSever(host,port)# 3.接收数据# 3.1 接收文件函数ReceiveFile(tcpserver)# 3.2 接收图片函数# ReceiveImg(tcpserver)# 3.3 接收视频帧# ReceiveFrame(tcpserver)# 4.关闭服务端tcpserver.close()

相关文章:

  • SpringBoot多线程与任务调度总结
  • android 手机主界面侧滑退出app问题
  • 测试bug分析
  • Anylogic Pro 8.8.x for Mac / for Linux Crack
  • 西北大学844计算机类考研-25级初试高分总攻略
  • 探究element-ui 2.15.8中<el-input>的keydown事件无效问题
  • 009:vue结合el-table实现表格行拖拽排序(基于sortablejs)
  • 微软发布安卓版Copilot,可免费使用GPT-4、DALL-E 3
  • 如何将语音版大模型AI接入自己的项目里(语音ChatGPT)
  • 计算机视觉与自然语言处理(Open AI)
  • 12月27日,每日信息差
  • 第四章 Consul服务注册与发现
  • Selenium库和ChromeDriver谷歌驱动最新版安装
  • 面试经典150题(50-53)
  • 垃圾收集器与内存分配策略
  • hexo+github搭建个人博客
  • canvas 绘制双线技巧
  • ECS应用管理最佳实践
  • js学习笔记
  • Netty 框架总结「ChannelHandler 及 EventLoop」
  • Python 基础起步 (十) 什么叫函数?
  • ReactNative开发常用的三方模块
  • Spring Cloud中负载均衡器概览
  • 从PHP迁移至Golang - 基础篇
  • 欢迎参加第二届中国游戏开发者大会
  • 基于OpenResty的Lua Web框架lor0.0.2预览版发布
  • 前端_面试
  • 适配iPhoneX、iPhoneXs、iPhoneXs Max、iPhoneXr 屏幕尺寸及安全区域
  • nb
  • 长三角G60科创走廊智能驾驶产业联盟揭牌成立,近80家企业助力智能驾驶行业发展 ...
  • ​secrets --- 生成管理密码的安全随机数​
  • !!【OpenCV学习】计算两幅图像的重叠区域
  • (pytorch进阶之路)扩散概率模型
  • (补)B+树一些思想
  • (附源码)node.js知识分享网站 毕业设计 202038
  • (过滤器)Filter和(监听器)listener
  • (经验分享)作为一名普通本科计算机专业学生,我大学四年到底走了多少弯路
  • (四) 虚拟摄像头vivi体验
  • (原+转)Ubuntu16.04软件中心闪退及wifi消失
  • (转)Spring4.2.5+Hibernate4.3.11+Struts1.3.8集成方案一
  • (转)用.Net的File控件上传文件的解决方案
  • *(长期更新)软考网络工程师学习笔记——Section 22 无线局域网
  • **登录+JWT+异常处理+拦截器+ThreadLocal-开发思想与代码实现**
  • .NET Core 项目指定SDK版本
  • .NET Framework 4.6.2改进了WPF和安全性
  • .net oracle 连接超时_Mysql连接数据库异常汇总【必收藏】
  • .net 简单实现MD5
  • .net 生成二级域名
  • .NET/C# 获取一个正在运行的进程的命令行参数
  • /var/log/cvslog 太大
  • @Conditional注解详解
  • [20181219]script使用小技巧.txt
  • [Android Studio 权威教程]断点调试和高级调试
  • [BJDCTF2020]The mystery of ip1
  • [BZOJ]4817: [Sdoi2017]树点涂色