I need to pass some strings of data between a Java application and a python script on a local Windows machine. So, I decided to do so with a Java socket server that is communicating with TCP to a python client. The Java creates two threads to handle two socket connections over the ports 9998 and 9999 of the localhost. I use port 9998 to handle incoming messages, while I use port 9999 to handle sending messages. My two applications run smoothly for the first few messages sent/received, and at some point, it stops on the call that sends the string from Java to Python. Here is part of my code:
This Java class handles the creation of the socket server and the communication
public class ServerSocketConnection {
private int port;
private Socket socket;
private ServerSocket serverSocket;
private Logger logger;
private BufferedWriter out;
private BufferedReader in;
public ServerSocketConnection(int port) {
this.port = port;
logger = App.getLogger();
}
// Create a server for a socket connection
public void createServer() {
try {
// Create a server socket
serverSocket = new ServerSocket(port);
// Socket creation
socket = serverSocket.accept();
// Create a print writer
out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
// Create a buffered reader
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (IOException e) {
logger.severe("Error creating server socket");
}
}
// Close the server socket
public void closeServer() {
try {
serverSocket.close();
} catch (IOException e) {
logger.severe("Error closing server socket");
}
}
public void sendMessage(String message) {
try {
// Sending the byte lenght of the message
byte[] ptext = message.getBytes("UTF-8");
send(String.valueOf(ptext.length));
// Sending the message
send(message);
} catch (IOException e) {
logger.severe("Error sending message:" + e.getMessage());
}
}
private void send(String message) throws IOException {
out.write(message);
out.newLine();
out.flush();
}
public String receiveMessage() {
try {
return in.readLine();
} catch (IOException e) {
logger.severe("Error receiving message");
return null;
}
}
This is the Java Thread handling the sending of the messages. It gets the message to send from a Queue that is shared between other threads.
public class SendToPlatform implements Runnable {
private static final int PORT = 9999;
private Thread worker;
private AtomicBoolean running;
private AtomicBoolean stopped = new AtomicBoolean(false);
private BlockingQueue<String> queueOut;
private Logger logger;
private ServerSocketConnection serverSocketConnection;
public SendToPlatform(BlockingQueue<String> queueOut, AtomicBoolean running) {
this.queueOut = queueOut;
this.running = running;
this.logger = App.getLogger();
serverSocketConnection = new ServerSocketConnection(PORT);
}
public void run() {
stopped.set(false);
serverSocketConnection.createServer();
while (running.get()) {
socketSender();
}
stopped.set(true);
}
private void socketSender() {
if (!queueOut.isEmpty()) {
String element = null;
try {
element = queueOut.poll(1000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
logger.severe("SendToPlatform: InterruptedException: " + e.getMessage());
}
serverSocketConnection.sendMessage(element);
}
}
}
This is the python thread that is used to receive the message from the Java socket server:
def __socket_reading_no_server(self, queue_input : queue.Queue, is_running : bool):
HOST = "localhost"
PORT = 9999
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
while is_running:
data = s.recv(4)
message_size = int(data.decode('UTF-8').strip())
data = s.recv(min(message_size + 2, 1024))
message = data.decode('UTF-8').strip()
queue_input.put(message)
s.close()
And this method is lanched as a thread with these instructions:
input_thread = threading.Thread(target=self.__socket_reading_no_server , args =(self.__queue_input, self.__running, ), daemon=True)
input_thread.start()
By debugging, logging, and using Wireshark to understand the problem in my code, I concluded that I have a recurrent problem with the out.write
instruction that blocks while sending the message after around 10 messages are sent correctly. The pending message gets released when I close the socket connection. I tried using PrintWriter
and DataOutputStream
instead of BufferedWriter,
but the same problem occurred. I tried not sending the length of the message before sending the string to adapt the s.recv()
size, but the same problem occurred.
I'm new to socket programming, and probably I did something incredibly wrong, but I cannot find where the problem is. Maybe is there a better way to pass data between processes that I'm unaware of that I can use for my needs instead of sockets?
Edits after @absuu answer
After applying the corrections suggested in the answer I still get the same problem of out.write
in the send method blocking while trying to write into the socket. I edited my code as follows:
public class ServerSocketConnection {
[...]
public void sendMessage(String message) {
try {
send(message);
} catch (IOException e) {
logger.severe("Error sending message:" + e.getMessage());
}
}
private void send(String message) throws IOException {
message += "\r\n";
byte[] ptext = message.getBytes("UTF-8");
out.write(String.format("%2d",ptext.length));
out.write("\r\n");
out.flush();
out.write(new String(ptext));
logger.info("Data sent");
out.flush();
}
}
I also increased the s.recv
size but nothing changed