Java client and a C++ server send and receive via TCP Socket

12,337

PrintWriter buffer (when autoflush is true) is only flushed by calling println or printf. Calling print may not flush the buffer (Javadoc). Try calling println or use a OutputStreamWriter directly and flush(). Be aware of using the right charset (You can set it up in OutputStreamWriter constructor).

Share:
12,337
Admin
Author by

Admin

Updated on June 09, 2022

Comments

  • Admin
    Admin almost 2 years

    I have a C++ server and two clients (ruby and java). Everything is running on a 64-bit linux-machine (java 1.7.0_17) The ruby client is fully working, but the java version makes problems.

    In Java I tried to send a String from the client to the server. Actually the Server received the entire String, but the server thinks there is still something more to receive.

    The ruby client looks a little bit like this:

    socket = TCPSocket.open(@options[:host],@options[:port])
    test = "Hello, World"
    socket.puts test
    socket.shutdown 1
    response = socket.gets
    

    Everything here is working fine. The ruby client sends a string. The server receives that string and sends a reply.

    The Java Version looks like:

    String ip = "127.0.0.1";
    int port = 6686;
    java.net.Socket socket = new java.net.Socket(ip,port);
    OutputStreamWriter out = new OutputStreamWriter(socket.getOutputStream());
    InputStreamReader in = new InputStreamReader(socket.getInputStream());
    
    String msg = "Hello, world!";
    
    //send
    PrintWriter pw = new PrintWriter(out, true);
    pw.print(msg);
    pw.flush();
    // I also tried: out.write(msg); out.flush(); nothing changed
    
    //receive the reply
    BufferedReader br = new BufferedReader(in);
    char[] buffer = new char[300];
    int count = br.read(buffer, 0, 300);
    String reply = new String(buffer, 0, count);
    System.out.println(reply);
    
    socket.close();
    

    On the other side there is a C++ Server:

    string receive(int SocketFD) {
       char buffer[SOCKET_BUFFER_SIZE];
       int recv_count;
    
       // empty messagestring
       string message = "";
    
       // empty buffer
       memset(buffer, 0, sizeof(buffer));
    
       while ((recv_count = recv(SocketFD, buffer, sizeof(buffer) - 1, 0)) > 0) {
          /*if (recv_count == -1) {
             cout << "failed." << endl;
             break;
          }*/
          cout << recv_count << endl;
          if (ECHO_SOCKETS) cout << "received: " << buffer << endl;
    
          message.append(buffer);
          memset(buffer, 0, sizeof(buffer));
    
          if (ECHO_SOCKETS) cout << "message is now: " << message << endl;
    
       }
       return message;
    }
    

    The server output from the Java-message is:

    13
    received: Hello, world!
    message is now: Hello, world!
    

    and then nothing happens. The problem is that:

    recv(SocketFD, buffer, sizeof(buffer) - 1, 0)
    

    is catched in an endless loop (or something like that). If I kill the Java-client process or I type something like:

    pw.print(msg);
    out.close();
    

    the output on the server side is:

    _sending reply: "Request unrecognized/invalid" request="Hello, world!"
    send reply success
    now close connection
    

    This output is right (except "send reply success"), but in case of adding:

    out.close();
    

    the client can't receive the reply of the server. Because the Socket is closed.

    java.net.SocketException: Socket is closed
    at java.net.Socket.getInputStream(Socket.java:864)
    at MyServer.writeMessage(MyServer.java:56)
    at MyServer.test(MyServer.java:42)
    at MyServer.main(MyServer.java:30)
    

    Edit

    I tried to call pw.flush(); and different delimiters like "\n", "\r", "\r\n" and "\n\r" but the server still thinks there is still something to read. I also tried to use DatagramSockets:

    java.net.DatagramSocket dSocket = new java.net.DatagramSocket();
    InetAddress address = InetAddress.getByName("localhost");
    String msg = "Hello, world!";
    byte[] buf = msg.getBytes();
    java.net.DatagramPacket packet = new DatagramPacket(buf, buf.length, address, 6686);
    

    But the server can't accept the packet.

    Solution

    The ruby-client does something like a socket.shutdownOutput(); (ruby: socket.shutdown 1) after the call of puts. I changed the java-client-code:

    out.write(msg);
    socket.shutdownOutput();
    

    and it works!

    As @Charly said: I have to define a "protocol". In my case I'm not allowed to change any communication related code (in the server and the ruby-client) because this functionality is used by a another group of researchers. So I've to modify my java-client in that way, that it does the exact same things at the exact same time as the ruby-client (something like a protocol).