Python套接字tcp与ROS上的子进程通信



我试图通过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()

最新更新