6

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

MartinO.
  • 63
  • 1
  • 1
  • 4

3 Answers3

2

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

Charly
  • 193
  • 1
  • 8
  • I already used pw.flush() but nothing was changed. Now I tried to use OutputStreamWriter directly: out = new OutputStreamWriter(socket.getOutputStream(), Charset.forName("ISO-8859-1")); ... and out.write(msg); out.flush(); but same result. – MartinO. Apr 10 '13 at 16:56
  • I changed the java-client source – MartinO. Apr 10 '13 at 17:06
  • I really don't know c++ but shouldn't you have some kind of delimiter to indicate the end of the message to the server ? As i see it, your server only send the echo when the connection is closed... For example the readLine() on a BufferedReader in Java will only return when reading a \n or a \r. – Charly Apr 10 '13 at 17:55
  • I' already tried something like: "Hello, world!\n" but the server prints all out and hangs at the same line. As I mentioned at the end of my post, I think I need a special delimiter, but why does it work in ruby? And of course I don't what to write the server-code depending on the programming language used by the client. – MartinO. Apr 10 '13 at 18:16
  • Of course you cannot write a server based on the programming language used by the client. Both must be compliant, that's why you need to define a kind of "protocol" between the two. If you decide that the client must send a String and a "\n", that's how it is and you do the same in Ruby and Java. In your c++ code, just test whenever this symbol appears and you can go out of your loop and send the reply. About the Ruby, I don't really know but it seems that "puts" write a newline sequence at the end. – Charly Apr 10 '13 at 20:29
  • So, puts makes a newline. I tried "\n", "\r", "\n\r" and "\r\n" nothing helped. BUT I realized that 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! – MartinO. Apr 11 '13 at 07:45
0

Close the stream respectively flush it in a way like this:

DataOutputStream dataOut = new DataOutputStream(socket.getOutputStream());
dataOut.writeUTF(s);
dataOut.flush();
Misch
  • 10,350
  • 4
  • 35
  • 49
Jan Piel
  • 540
  • 2
  • 6
  • Hi Misch, DataOutputStream, writeUTF(msg) and flush(); doesn't work. recv_count is 15! on the server (I would accept 13 or 14). And the output: cout << "received: " << buffer << endl; is empty. There are no characters. – MartinO. Apr 09 '13 at 15:08
0
while ((recv_count = recv(SocketFD, buffer, sizeof(buffer) - 1, 0)) > 0) {
      if (recv_count == -1) {

I don't know what your problem is but this code is certainly nonsense. It is impossible for the inner test ever to succeed.

user207421
  • 305,947
  • 44
  • 307
  • 483