1

I need to send a message from a java client program to a python server program.

Here is my code:

Java client:

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;

public class Client {
    public static void main(String[] args) throws IOException {
        // need host and port, we want to connect to the ServerSocket at port 7777
        Socket socket = new Socket("localhost", 7777);
        System.out.println("Connected!");

        // get the output stream from the socket.
        OutputStream outputStream = socket.getOutputStream();
        // create a data output stream from the output stream so we can send data through it
        DataOutputStream dataOutputStream = new DataOutputStream(outputStream);

        System.out.println("Sending string to the ServerSocket");

        // write the message we want to send
        dataOutputStream.writeUTF("Hello from the other side!");
        dataOutputStream.flush(); // send the message
        dataOutputStream.close(); // close the output stream when we're done.

        System.out.println("Closing socket and terminating program.");
        socket.close();
    }
}

Python server:

from multiprocessing.connection import Listener
address = ('localhost',7777)
while True:
    with Listener(address, authkey=None) as listener
        with listener.accept() as conn:
            print(conn.recv())

When I try to execute this, I get the following error in Python:

OSError: got end of file during message

What am I doing wrong?

josh
  • 21
  • 1
  • Can you explain why you're using the multiprocessing module when there's no multiprocessing involved? –  Nov 09 '21 at 08:14

2 Answers2

0

Use of the multiprocessing module seems inappropriate in this case and is the root cause of your problem. Here's a simplified Python server that demonstrates how you could achieve your objective. Note that the server terminates after accepting and handling any single connection:

import socket

def server():
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.bind(('0.0.0.0', 7777))
        s.listen()
        conn, _ = s.accept()
        with conn:
            while (data := conn.recv(8192)):
                print(data.decode())

if __name__ == '__main__':
    server()
  • Why can't I use multiprocessing.connection.Listener instead of socket? I thought they work pretty much the same way? See for example [this question](https://stackoverflow.com/questions/60997100/socket-vs-multiprocessing-connection-listener-in-python) and the [docs](https://docs.python.org/3/library/multiprocessing.html) for the multiprocessing library. – josh Nov 09 '21 at 08:25
  • @josh 2 questions. 1) Are both client and server running on the same machine? 2) Are either or both client and server on Windows or Unix type systems? Once I know that I'll put together a multiprocessing version that should work for you –  Nov 09 '21 at 08:33
  • Yes, they're on the same machine and it runs Windows. – josh Nov 09 '21 at 08:35
0

The issue here is that the recv* functions of the multiprocessing connection expect to get a 32-bit preamble in the message that indicates the actual amount of data being transmitted. So here's what the Java part needs to look like (I haven't bothered about buffered IO - just keeping things to bare bones):

import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;

public class Client {

    public static void main(String[] args) throws IOException {
        String message = "Talking isn't doing. It is a kind of good deed to say well; and yet words are not deeds.";
        try (Socket socket = new Socket("localhost", 7777)) {
            try (DataOutputStream out = new DataOutputStream(socket.getOutputStream())) {
                byte[] dts = message.getBytes();
                out.writeInt(dts.length);
                out.write(dts);
            }
        }
    }
}

Then, your Python server can look something like this:

from multiprocessing.connection import Listener

def main():
    listener = Listener(address=('0.0.0.0', 7777), family='AF_INET', authkey=None)
    with listener.accept() as conn:
        print(conn.recv_bytes().decode())
            

if __name__ == '__main__':
    main()

So, this means that your original problem is due to recv() looking at the first 4 bytes and interpreting that as the length of incoming data. But that would equate to something much larger than was actually being sent.

  • Ok this works but I'm not sure why. Can you explain what you're trying to do inside the private static byte[] net(int n) function? Also, will this work irrespective of how small or how large the message size is? – josh Nov 09 '21 at 10:50
  • The *net* function takes a 32-bit int and expresses it as a 4-byte byte array. The message is therefore limited to 2,147,483,647 bytes (0x7fffffff) –  Nov 09 '21 at 11:35