网站建设前期调研公司汇报专业网站建设专家
python socket网络编程
将ros机器人摄像头捕捉的画面在上位机实时显示,需要用到socket网络编程,提供了TCP和UDP两种方式
TCP服务器端代码:
- 创建TCP套接字: 
s = socket(AF_INET, SOCK_STREAM)创建了一个TCP套接字。SOCK_STREAM表示这是一个TCP套接字,而不是UDP的SOCK_DGRAM。
 - 绑定地址: 
s.bind(addr)将套接字绑定到一个特定的地址和端口上。
 - 监听连接: 
s.listen(1)使套接字开始监听连接请求。参数1表示最多可以有一个待处理的连接。
 - 接受连接: 
conn, addr = s.accept()阻塞,直到客户端连接。一旦客户端连接,它将返回一个新的套接字对象和客户端的地址。
 - 接收和处理数据: 
- 在一个循环中,
data = conn.recv(921600)从新的套接字对象接收数据。 - 使用 
cv2.imdecode和cv2.imshow处理和显示接收到的图像数据。 - 如果按下 ‘q’ 键,循环将终止。
 
 - 在一个循环中,
 - 清理: 
conn.close()关闭客户端连接。s.close()关闭监听套接字。cv2.destroyAllWindows()关闭所有OpenCV窗口。
 
import numpy as np
import cv2
from socket import *# 创建TCP套接字
s = socket(AF_INET, SOCK_STREAM)
addr = ('127.0.0.1', 8080)
s.bind(addr)
s.listen(1)  # 监听连接,参数1表示最大连接数print("Waiting for a connection...")
conn, addr = s.accept()  # 接受连接
print(f"Connection from {addr}")try:while True:data = conn.recv(921600)  # 接收数据if not data:break  # 如果没有数据,退出循环receive_data = np.frombuffer(data, dtype='uint8')r_img = cv2.imdecode(receive_data, 1)r_img = r_img.reshape(480, 640, 3)cv2.putText(r_img, "server", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)cv2.imshow('server_frame', r_img)if cv2.waitKey(1) & 0xFF == ord('q'):break
finally:conn.close()  # 关闭连接s.close()  # 关闭套接字cv2.destroyAllWindows() 
TCP客户端:
- 创建TCP套接字: 
- 同样使用 
s = socket(AF_INET, SOCK_STREAM)创建一个TCP套接字。 
 - 同样使用 
 - 连接到服务器: 
s.connect(addr)尝试连接到服务器的地址和端口。
 - 捕获和处理图像: 
- 在一个循环中,使用 
cv2.VideoCapture捕获图像,并通过cv2.flip对图像进行处理。 
 - 在一个循环中,使用 
 - 发送图像数据: 
- 创建一个新线程 
th来调用send_img函数,并使用th.start()启动线程。 send_img函数中,使用cv2.imencode将图像编码为JPEG格式,然后使用s.sendall(send_data)将图像数据发送到服务器。
 - 创建一个新线程 
 - 显示图像: 
- 在本地显示处理过的图像,并检查是否按下了 ‘q’ 键来决定是否退出循环。
 
 - 清理: 
s.close()关闭TCP套接字。cv2.destroyAllWindows()关闭所有OpenCV窗口。
 
import cv2
import threading
from socket import *def send_img():_, send_data = cv2.imencode('.jpg', img, [cv2.IMWRITE_JPEG_QUALITY, 50])s.sendall(send_data)  # 发送所有数据print(f'已发送{len(send_data)}Bytes的数据')addr = ('127.0.0.1', 8080)
cap = cv2.VideoCapture(0)s = socket(AF_INET, SOCK_STREAM)
s.connect(addr)  # 连接到服务器try:while True:_, img = cap.read()img = cv2.flip(img, 1)th = threading.Thread(target=send_img)th.setDaemon(True)th.start()cv2.putText(img, "client", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)cv2.imshow('client_frame', img)if cv2.waitKey(1) & 0xFF == ord('q'):break
finally:s.close()  # 关闭套接字cv2.destroyAllWindows() 
- 导入必需的库: 
sys和os是Python的标准库,用于访问与Python解释器和操作系统交互的一些功能。numpy是一个用于数值计算的库。cv2是OpenCV库的Python接口,用于图像处理和计算机视觉任务。threading和time是Python的标准库,分别用于多线程编程和时间相关的功能。socket是Python的标准库,用于网络通信。
 - 创建一个UDP套接字: 
s = socket(AF_INET, SOCK_DGRAM)这行代码创建了一个新的UDP套接字。
 - 绑定套接字到地址: 
addr = ('127.0.0.1', 8080)这行代码定义了一个地址,其中127.0.0.1是本机的IP地址,8080是端口号。s.bind(addr)这行代码将套接字绑定到指定的地址。
 - 接收和处理数据: 
- 这个脚本进入一个无限循环,等待接收数据。
 data, _ = s.recvfrom(921600)这行代码从套接字接收数据,最多接收921600字节的数据。receive_data = np.frombuffer(data, dtype='uint8')这行代码将接收到的数据转换为一个numpy数组。r_img = cv2.imdecode(receive_data, 1)这行代码解码接收到的数据,将其转换为一个OpenCV图像对象。r_img = r_img.reshape(480, 640, 3)这行代码将图像重塑为480x640的大小,并指定该图像有3个颜色通道。cv2.putText(...)这行代码将文本 “server” 画到图像上。cv2.imshow('server_frame', r_img)这行代码显示处理后的图像。if cv2.waitKey(1) & 0xFF == ord('q'):这行代码检查是否按下了键 ‘q’,如果是,则退出循环。
 - 清理: 
cv2.destroyAllWindows()这行代码关闭所有OpenCV窗口。
 
UDP服务器端:
import sys, osimport numpy as np
import cv2, threading, time
from socket import *s = socket(AF_INET, SOCK_DGRAM)
# addr = ('192.168.64.1', 8080)
addr = ('127.0.0.1', 8080)          # 127.0.0.1表示本机的IP,相当于我和“自己”的关系
s.bind(addr)
while True:data, _ = s.recvfrom(921600)receive_data = np.frombuffer(data, dtype='uint8')r_img = cv2.imdecode(receive_data, 1)r_img = r_img.reshape(480, 640, 3)cv2.putText(r_img, "server", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)cv2.imshow('server_frame', r_img)if cv2.waitKey(1) & 0xFF == ord('q'):breakcv2.destroyAllWindows()
 
- 导入必需的库: 
- 同样导入了
numpy,cv2,threading,time和socket库。 
 - 同样导入了
 - 定义 
send_img函数:send_img函数中,通过s.sendto(send_data, addr)语句将图像数据发送到指定的地址。- 输出已发送的数据大小,并通过 
s.close()关闭套接字。 
 - 设置地址: 
addr = ('127.0.0.1', 8080)设置了目标地址和端口。
 - 初始化摄像头: 
- 通过 
cv2.VideoCapture(0)初始化摄像头,并进入一个无限循环。 
 - 通过 
 - 捕获和处理图像: 
- 在循环中,通过 
_, img = cap.read()语句捕获图像。 - 通过 
cv2.flip(img, 1)语句将图像进行水平翻转。 
 - 在循环中,通过 
 - 创建并启动发送图像数据的线程: 
- 创建一个新的UDP套接字。
 - 创建一个新线程 
th,并将send_img函数设置为该线程的目标。 - 通过 
th.setDaemon(True)将线程设置为守护线程,这意味着主程序退出时,该线程也会退出。 - 通过 
cv2.imencode('.jpg', img, [cv2.IMWRITE_JPEG_QUALITY, 50])语句将图像编码为JPEG格式,质量设置为50。 - 通过 
th.start()语句启动线程。 
 - 显示图像: 
- 通过 
cv2.putText(...)和cv2.imshow('client_frame', img)语句在本地显示图像,并在图像上添加了文本 “client”。 
 - 通过 
 - 退出条件: 
- 如果按下’q’键,通过 
cv2.waitKey(1) & 0xFF == ord('q')语句检测到这一条件,并退出循环。 
 - 如果按下’q’键,通过 
 - 清理: 
- 通过 
cv2.destroyAllWindows()语句关闭所有OpenCV窗口。 
 - 通过 
 
该脚本应该与你之前提供的服务器脚本配合使用,服务器脚本用于接收图像数据,而这个客户端脚本用于发送图像数据。
UDP客户端:
import numpy as np
import cv2, threading, time
from socket import *def send_img():s.sendto(send_data, addr)print(f'已发送{img.size}Bytes的数据')s.close()# input('>>')# addr = ('192.168.43.106', 8080)
addr = ('127.0.0.1', 8080)          # 127.0.0.1表示本机的IP,相当于我和“自己”的关系
cap = cv2.VideoCapture(0)
while True:_, img = cap.read()img = cv2.flip(img, 1)s = socket(AF_INET, SOCK_DGRAM)th = threading.Thread(target=send_img)th.setDaemon(True)_, send_data = cv2.imencode('.jpg', img, [cv2.IMWRITE_JPEG_QUALITY, 50])th.start()cv2.putText(img, "client", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)cv2.imshow('client_frame', img)if cv2.waitKey(1) & 0xFF == ord('q'):breakcv2.destroyAllWindows()
