我试图通过ROS mymetric上的tcp python套接字发送/接收一个大型视频捕获图像。我需要使用子流程,因为ROS旋律在python2上运行,但我需要python3库。
我有一个服务器和一个客户端。
-
客户端:它是一个ROS节点,在
subprocess.Popen(['python3', Serverfile])
和client.connect(HOST_IP, HOST_PORT)
之后从相机节点发送接收到的视频捕获图像(其类型为"列表"( -
服务器:它是一个python3代码,用于接收数据并执行其功能,然后将新映像发送到客户端。
这是我的套接字代码。
import socket
import json
import sys
BUFSIZE = 4096
def _send(socket, send_data):
json_data = json.JSONEncoder().encode(send_data)
socket.sendall(json_data.encode())
def _recv(socket):
recv_data = socket.recv(BUFSIZE)
json_data = json.loads(recv_data.decode())
return json_data
class Server(object):
backlog = 1
client = None
def __init__(self, host, port):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # Error for using port
self.socket.bind((host, port))
self.socket.listen(self.backlog)
def __del__(self):
self.close()
def accept(self):
if self.client:
self.client.close()
self.client, self.client_addr = self.socket.accept()
return self
def send(self, data):
if not self.client:
raise Exception('Cannot send data, no client is connected.')
_send(self.client, data)
return self
def recv(self):
if not self.client:
raise Exception('Cannot receive data, no client is connected.')
return _recv(self.client)
def close(self):
if self.client:
self.client.close()
self.client = None
if self.socket:
self.socket.close()
self.socket =None
class Client(object):
socket = None
def __init__(self):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
def __del__(self):
self.close()
def connect(self, host, port):
self.socket.connect((host, port))
return self
def send(self, data):
if not self.socket:
raise Exception('You have to connect first before sending data.')
_send(self.socket, data)
return self
def recv(self):
if not self.socket:
raise Exception('You have to connect first before receiving data.')
return _recv(self.socket)
def close(self):
if self.socket:
self.socket.close()
self.socket = None
当我使用socket.SOCK_DGRAM
时,它会输出"消息太长"。所以我把它改为socket.SOCK_STREAM
,然后它现在输出"连接被拒绝">
这里有一个完整的例子,我使用zmq将图像从客户端传输到服务器
客户端
import rospy
import rospkg
import roslib
import sys
import rospy
import cv2
from std_msgs.msg import String
from sensor_msgs.msg import Image
from cv_bridge import CvBridge, CvBridgeError
import zmq
import numpy as np
class ClientThread():
def __init__(self):
self.context = zmq.Context()
self.footage_socket = self.context.socket(zmq.PUB)
self.footage_socket.connect('tcp://0.0.0.0:5556')
def callback(self, data):
try:
depth_image = bridge.imgmsg_to_cv2(data, "32FC1")
depth_array = np.array(depth_image, dtype=np.float32)
cv2.normalize(depth_array, depth_array, 0, 255, cv2.NORM_MINMAX)
encoded, buffer = cv2.imencode('.jpg', depth_array)
self.footage_socket.send(buffer)
cv2.imshow("Depth Image", depth_array)
cv2.waitKey(3)
except CvBridgeError as e:
print(e)
if __name__ == "__main__":
rospy.init_node('drone_client', anonymous=True)
bridge = CvBridge()
clien_ = ClientThread()
image_sub = rospy.Subscriber("/r200/depth/image_raw", Image, clien_.callback)
rospy.spin()
服务器:
from threading import Thread
import cv2
import numpy as np
import pickle
import struct
import zmq
class ServerTread(Thread):
def __init__(self):
Thread.__init__(self)
self.context = zmq.Context()
self.footage_socket = self.context.socket(zmq.SUB)
self.footage_socket.bind('tcp://*:5556')
self.footage_socket.setsockopt_string(zmq.SUBSCRIBE, np.unicode(''))
def run(self):
while True:
frame = self.footage_socket.recv()
npimg = np.frombuffer(frame, dtype=np.uint8)
source = cv2.imdecode(npimg, 1)
print(source.shape)
newthread = ServerTread()
newthread.start()
newthread.join()