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

3 Answers 3

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

Sign up to request clarification or add additional context in comments.

6 Comments

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.
I changed the java-client source
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.
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.
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.
|
0

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

DataOutputStream dataOut = new DataOutputStream(socket.getOutputStream());
dataOut.writeUTF(s);
dataOut.flush();

1 Comment

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

1 Comment

You are right. It's just an old code fragment. You can ignore it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.