繁体   English   中英

如何使用Java客户端和Python服务器通过套接字创建IPC?

[英]How to create IPC through sockets with a Java client and a Python server?

我正在尝试使两个进程通过本地套接字进行通信:Python 服务器和Java 客户端 我要在两者之间传递的数据由Protobuf对象的字节组成,其大小可变。 我希望连接保持打开状态并在程序结束之前使用该连接,因为我传递了许多需要处理的对象。

因为Protobuf对象的大小可变,所以我在发送包含该对象的真实消息/响应之前先发送消息/响应的大小。

目前,我正在使用Python端socketserver库中的TCPServer。 我实现了以下处理程序:

class MyTCPHandler(socketserver.BaseRequestHandler):
    """
    The request handler class for our server.

    It is instantiated once per connection to the server, and must
    override the handle() method to implement communication to the
    client.
    """

    def recv_all(self, n):
        # Helper function to recv n bytes or return None if EOF is hit
        data = b''
        while len(data) < n:
            packet = self.request.recv(n - len(data))
            if not packet:
                return None
            data += packet
        return data

    def handle(self):
        logger.debug("Beginning of handle cycle for client: {}.".format(self.client_address))

        while True:
            if True: # please disregard this if condition
                # Receive 4 bytes (1 int) denoting the size of the message
                data_length_bytes: bytes = self.recv_all(4)
                logger.debug('Received data_length: {}'.format(data_length_bytes))

                # If recv read an empty request b'', then client has closed the connection
                if not data_length_bytes:
                    break

                data_length: int = int.from_bytes(data_length_bytes.strip(), byteorder='big')
                data: bytes = self.recv_all(data_length).strip()

                response: bytes = data.upper()

                # Send length of response first
                self.request.sendall(len(response).to_bytes(4, byteorder='big'))
                # Send response
                self.request.sendall(response)

                logger.debug(
                    'Sent response to: {}. Size of response: {} bytes. Response: {}.'.format(self.client_address,
                                                                                             len(response),
                                                                                             response))


        logger.debug("End of handle cycle for client: {}.".format(self.client_address))

和以下客户端:

class SocketClient
{
    private static Socket socket;
    private int port;
    private DataOutputStream out;
    private DataInputStream in;

    SocketClient(int port)
    {
        this.port = port;
        this.createSocket();
    }

    private void createSocket() {
        InetAddress address;
        try {
            address = InetAddress.getByName("localhost");
            socket = new Socket(address, port);
            this.out = new DataOutputStream(socket.getOutputStream());
            this.in = new DataInputStream(socket.getInputStream());

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    byte[] sendMessageAndReceiveResponse(byte[] messageToSend){
        try {
            if(true) {  // again, please disregard this condition
                //Send the size of the message to the server
                this.out.writeInt(messageToSend.length);
                out.flush();

                this.out.write(messageToSend);
                out.flush();

                //Get the response message from the server
                int length = in.readInt();                    // read length of incoming message

                byte[] buffer = null;
                if(length>=0) {
                    buffer = new byte[length];
                    in.readFully(buffer, 0, buffer.length); // read the message
                }

                return buffer;
            }
        }
        catch (ConnectException exception) {
            System.out.println("ATTENTION! Could not connect to socket. Nothing was retrieved from the Python module.");
            exception.printStackTrace();
            return null;
        }
        catch (Exception exception)
        {
            exception.printStackTrace();
            return null;
        }
    }

    void close(){
        //Closing the socket
        try
        {
            in.close();
            out.close();
            socket.close();
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }

启动Python服务器后,我运行以下实验:

        SocketClient socketClient = new SocketClient(5000);

        byte[] response;

        // Case 1
        response = socketClient.sendMessageAndReceiveResponse("12345678".getBytes());
        System.out.println(new String(response));

        // Case 2
        response = socketClient.sendMessageAndReceiveResponse("123456781".getBytes());
        System.out.println(new String(response));

        // Case 3
        response = socketClient.sendMessageAndReceiveResponse("12345678123456781".getBytes());
        System.out.println(new String(response));


        socketClient.close();

情况1和情况3运作良好。 但是,当我在Python服务器端运行case 2时 ,得到以下日志:

DEBUG -- [handle()] Received data_length: b'\x00\x00\x00\t' # The '\t' shouldn't be here. A '\x09' should.

然后服务器抛出异常,退出连接。 每个8 <length <14的字符串都会发生这种情况。我在做什么错,有没有更简单的方法来实现我想要的?

我弄清楚了为什么我对8 <长度<14的消息有问题。

当length等于9时,我得到\\t字符。我注意到,如果将长度更改为10,它将变为\\n 到13, \\r 我意识到,有没有任何\\t奇迹般地出现。 Python由于某种原因将\\x09转换为\\t ,因为水平制表符\\t的ASCII码等于9!

当我在这一行中应用strip()函数时:

data_length: int = int.from_bytes(data_length_bytes.strip(), byteorder='big')

,Python删除了我的\\t ,实际上是我的\\x09 我的问题是剥离值之前先记录该值,因此我花了很长时间找出我的错误。

因此,解决方案是根本不使用strip() 我将当前的工作代码留在这里(至少用于测试),以供他人使用:

Python服务器处理程序:

class MyTCPHandler(socketserver.BaseRequestHandler):
    """
    The request handler class for our server.

    It is instantiated once per connection to the server, and must
    override the handle() method to implement communication to the
    client.
    """

    def recv_all(self, n):
        # Helper function to recv n bytes or return None if EOF is hit
        data = b''
        while len(data) < n:
            packet = self.request.recv(n - len(data))
            if not packet:
                return None
            data += packet
        return data

    def handle(self):
        while True:
            data_length_bytes: bytes = self.recv_all(4)

            # If recv read an empty request b'', then client has closed the connection
            if not data_length_bytes:
                break

            # DON'T DO strip() ON THE DATA_LENGTH PACKET. It might delete what Python thinks is whitespace but
            # it actually is a byte that makes part of the integer.
            data_length: int = int.from_bytes(data_length_bytes, byteorder='big')

            # Don't do strip() on data either (be sure to check if there is some error if you do use)
            data: bytes = self.recv_all(data_length)

            response: bytes = data.upper()

            self.request.sendall(len(response).to_bytes(4, byteorder='big'))
            self.request.sendall(response)

Java客户端保持不变,但是没有我出于调试原因而使用的if(true)条件。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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