简体   繁体   中英

Python socket tcp communication with subprocess on ROS

I tried to send/receive a large video capture image by tcp python socket on ROS-melodic. I need to use subprocess because ROS-melodic is running on python2 but I need python3 libraries.

I have a Server and a Client.

  • Client : It is a ROS node that sending the received video capture image(its type is 'list') from camera node after subprocess.Popen(['python3', Serverfile]) and client.connect(HOST_IP, HOST_PORT)

  • Server : It is a python3 code that receiving the data and doing its functions and then sending the new image to Client.

Here is my socket code.

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

It outputs 'Message too long' when I use socket.SOCK_DGRAM . So I changed it socket.SOCK_STREAM then it now outputs 'Connection refused'

Here is a full example, where I used zmq for transferring images from client to server

Client

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()

Server:

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()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM