Hot questions for Using Transmission Control Protocol in buffer

Question:

Im writing a tcp client in Java which is supposed to receive data from some server.

As far as I know if client cannot handle incoming data from server OS starts buffering data. But what happen if the buffer is full? Is that behaviour configurable?

I mean I want to throttle server data stream till client can handle data so it's not lost. Is it possible?


Answer:

What your describing is called TCP Windowing.

There's a nice explanation here

Excerpt:

When discussing TCP Windows, we are most often referring to the TCP Receive Window. Simply put, a TCP Receive Window is a buffer on each side of the TCP connection that temporarily holds incoming data. The data in this buffer is sent to the application, clearing more room for incoming data. If this buffer fills up, the receiver of the data will alert the sender that no more data can be received until the buffer is cleared. There are several more details involved, that that is the basic function. A device advertises the current size of its TCP Window in the TCP Header information.

It is possible to throttle the stream by closing the window, although you can just as easily stop reading from the buffer and let the protocol do its job.

Some of the messaging products manage this by using a secondary buffer's to minimize the impact of getting overrun by data. Most of these products are mainly UDP broadcast/multicast though. At some level though, if your client can't keep up, your going to have issues.

Question:

I'm having the following problem in java: I am developing and app using java.net.Socket. It looks like that: There is a server with a thread which accepts and adds new client, and another thread which reads data from sockets and does "something" with it. Next to it there are clients. Client has data reader thread as well as a separate thread. I send the data as simple as:

socket.getOutputStream().write((content+"\n").getBytes());

on the client side and read it on the server like:

try {
    BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    String received;
    while(true) {
        try {
            reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            received = reader.readLine();
            if(received == null) {
                break;
            }
            System.out.println("SERVER " + received);
            increaseReceivedCounter(1);
        } catch(SocketException e) {
            break;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
} catch (IOException e) {
    e.printStackTrace();
} finally {
    System.out.println("SERVER RECEIVED "+ getReceivedCounter() + " MESSAGES!");
}

Now I just set the client to send some amount of messages like this:

try {
    int n = 1000;
    System.out.println("sending "+ n +" messages to " + client);
    for(int i=0 ; i<n ; ++i) {
        socket.getOutputStream().write((content+"\n").getBytes());
    }
    System.out.println("done sending " + n + " messages");
} catch (IOException e) {
    e.printStackTrace();
}

The problem is that not all of the messages are transferred to a server. I have been looking for some solution for this but didn't manage to achieve 100% reliability. Is it even possible? I also tried with read instead of readLine but the result is the same: sometimes even 90% data loss. I think while server is working on the received data it ignores incoming packets and they're just lost.

Edit

Sockets initializations:

serverSocket = new ServerSocket(Server.PORT);//PORT = 9876, whatever

for the data reader on server side:

socket = serverSocket.accept();

on the client:

socket = new Socket("127.0.0.1", Server.PORT)

Answer:

This is not an 'efficiency issue'. It is a bug in your code.

The problem is that not all of the messages are transferred to a server.

No, the problem is that you are losing data at the server. This is because you keep recreating BufferedReaders. You should create it once for the life of the socket.

reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));

Remove this line.

The way you have it, you will lose data every time the prior BufferedReader has, err, buffered.

You also need to close the socket.

Question:

I am trying to understand netty buffers and watermarks.

As a test case, I have a netty server which writes to a client, the client is blocked (essentially has a sleep of 10 seconds between each read)

  • Under normal I/O TCP sender would be throttled (sending is slowed down because of flow control) if the receiver is blocked, this is not the case here. The sender seems to keep writing and flushing data on each send. Where is this data being written? Is there going to be Flow control in the netty's flush() as well? See: https://en.wikipedia.org/wiki/Transmission_Control_Protocol#Flow_control

  • Is it is being written to an OS or TCP buffer, does netty channel have an internal buffer as well? If so how can I configure it?

  • I track bytesBeforeUnwritable but they do not seem to be decreasing

  • What is the default High and Low Watermark? I have not set anything in my application. Is there any way to use this instead?

Code below:

@Override
    public void channelRead(final ChannelHandlerContext ctx, Object msg) {

        if (server2OutboundChannel.isActive()) {
            if(server2OutboundChannel.isWritable()) {
                server2OutboundChannel.writeAndFlush(msg).addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture future) {
                        if (future.isSuccess()) {
                            // was able to flush out data, start to read the next chunk
                            //System.out.println(server2OutboundChannel.bytesBeforeUnwritable());
                            ctx.channel().read();
                        } else {
                            future.channel().close();
                        }
                    }
                });
            }else{
                System.out.println("Channel is no longer writeable");
                System.out.println(server2OutboundChannel.bytesBeforeUnwritable());
                System.out.println(server2OutboundChannel.bytesBeforeWritable());
            }
        }
    }

Detailed steps to re-create with end-to-end source code:

https://github.com/nipunarora/nettyDuplicator/tree/master/src/main/java/org/columbia/parikshan/proxy

  • Compile and Build:

    mvn package

  • Start the server

    sh scripts/Server.sh 3380

  • Start the netty proxy

    sh scripts/nettyProxy.sh -l 0.0.0.0:3379 -o 127.0.0.1:3380

  • Start the client

    sh scripts/Client.sh 127.0.0.1 3379

  • send "hello" as std input in client

  • netty blocks sending after some time and the bytesTillUnwritable do not decrease.


Answer:

Where is this data being written? Is there going to be Flow control in the netty's flush() as well?

The data went to ChannelOutboundBuffer. There is no Flow control like tcp. The data will be kept in ChannelOutboundBuffer until there is space in tcp's send buffer.

Is it is being written to an OS or TCP buffer, does netty channel have an internal buffer as well? If so how can I configure it?

Netty has ChannelOutboundBuffer which keep data before send to OS'buffer. You can configure it like below.

    Bootstrap bootstrap = new Bootstrap();
    bootstrap.option(ChannelOption.SO_RCVBUF, soRcvBufSize);
    bootstrap.option(ChannelOption.SO_SNDBUF, soSndBufSize);
    bootstrap.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, writeBufferHighWaterMark);

I track bytesBeforeUnwritable but they do not seem to be decreasing

I write a sample code that server write to a blocked client

Your proxy's AUTO_READ is false. NettyProxyFrontendHandler#channelRead will only be called when ctx.channel().read() (in the future listener) is called. The listener will be called after writeAndFlush is completed. writeAndFlush will generate a task and the task will is done when the msg is write to OS's buffer. If OS's buffer is filled, the task will be blocked. There is no chance that netty's buffer will become unwritable, it is always writeable.

What is the default High and Low Watermark? I have not set anything in my application. Is there any way to use this instead?

You can check the defualt water mark in DefaultChannelConfig -> WriteBufferWaterMark.DEFAULT. When data in ChannelOutboundBuffer > high water mark the isWritable return false, < low water mark return true.

 /**
 * Returns {@code true} if and only if the I/O thread will perform the
 * requested write operation immediately.  Any write requests made when
 * this method returns {@code false} are queued until the I/O thread is
 * ready to process the queued write requests.
 */
boolean isWritable();

Question:

My code just do a simple task send a text from client's console to server and receive a reply. But my code doesn't work though. I keep sending text to server and no reply sending back. I have done a several example that plus 2 number given from client. I do this the same way but i can't figure out what is the problem.

Server:

public class Server {
    public static void main(String[] args) {
        try {
            ServerSocket server = new ServerSocket(8);
            Socket client = server.accept();
            BufferedReader inFromClient = new BufferedReader(new InputStreamReader(client.getInputStream()));
            BufferedWriter outToClient = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
            String in = inFromClient.readLine(),out;
            while(in!=null){
                out = in+" from server";
                outToClient.write(out);
                outToClient.newLine();
                outToClient.flush();
            }
            inFromClient.close();
            outToClient.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

Client:

public class Client {
    public static void main(String[] args) {
        try {
            Socket client = new Socket("localhost", 8);
            System.out.println("Connected to server");
            BufferedReader inFromServer = new BufferedReader(new InputStreamReader(client.getInputStream()));
            BufferedWriter outToServer = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
            Scanner input = new Scanner(System.in);
            String strClient,strServer;
            while(true){
                System.out.print("Client: ");
                strClient = input.nextLine();
                outToServer.write(strClient);
                strServer = inFromServer.readLine();
                System.out.print("Server: ");
                System.out.println(strServer);
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

Answer:

There are several problems with your code:

  1. Your server is expecting to read a line and you're only writing text without a newline symbol:

Reading a line in server with: inFromClient.readLine()

Writing text without newline in client: outToServer.write(strClient); Change this to outToServer.write(strClient + "\n");


  1. You don't flush the writer of the client. Add a outToServer.flush(); after the line outToServer.write(...);

  1. You only read 1 line in the server and don't read inside the loop again.

EDIT: To make it easier i'll post the corrected code here: (I've tried it and it works like a charm)

Client:

public class Client {
    public static void main(String[] args) {
        try (Socket client = new Socket("localhost", 8);
            BufferedReader inFromServer = new BufferedReader(new InputStreamReader(client.getInputStream()));
            BufferedWriter outToServer = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
            Scanner input = new Scanner(System.in)) {

            System.out.println("Connected to server");
            String strClient,strServer;

            while(true){
                System.out.print("Client: ");
                strClient = input.nextLine();
                outToServer.write(strClient);
                outToServer.newLine();
                outToServer.flush();
                strServer = inFromServer.readLine();
                System.out.println("Server: " + strServer);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Server:

public class Server {
    public static void main(String[] args) {
        try (ServerSocket server = new ServerSocket(8);
            Socket client = server.accept();
            BufferedReader inFromClient = new BufferedReader(new InputStreamReader(client.getInputStream()));
            BufferedWriter outToClient = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()))) {

            String in = inFromClient.readLine(), out;
            while(in != null){
                out = in + " from server";
                outToClient.write(out);
                outToClient.newLine();
                outToClient.flush();
                in = inFromClient.readLine();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Please remark that this solution uses Javas ARM (Automatic resource management) for autoclosing streams and sockets. So this will not work before java 1.7!

Question:

I need to continuously listen for messages from my C# TCP server, so I do it in separate thread:

private void StartMessageReceivingLoop()
{       
    new Thread(){
        public void run()
        {
            String msg = null;

            try
            {
                msg = inputStream.readLine(); // inputStream is a BufferedReader instance.
            } 
            catch (IOException e)
            {
                e.printStackTrace();
            }

            if (msg != null && msg != "")
                NotifyAndForwardMessage(msg); // Notify listeners about the message.

            run(); // Next iteration.
        }
    }.start();
}

What's wrong with my approach? Why am I getting a StackOverflowError? I'm guessing that run() is invoked incredibly fast because BufferedReader.readLine() is non-blocking, but what can I do about it?


Answer:

Don't call run() within run(). This is not a recursive function. If you want to keep reading until some condition, wrap this in a while loop. By calling the method you are executing while you are executing it, you are creating another stack frame. What you really want is just to loop.

public void run() {
   String msg = null;
   while(true) {  // Or whatever your exit condition is...
      try {
         msg = inputStream.readLine();
      } catch(IOException e) {
         // Handle properly.
      }
      if (msg != null && msg != "") {
          NotifyAndForwardMessage(msg);
      }
   }
}

To help illustrate, it kind of works like this...

Thread.start()
   + run() // 1 (called by thread)
      + run() // 2 (called by previous run)
         + run() //3 (called by previous run)
            +etc... where you'll eventually run out of stack space.

Question:


Answer:

The point is basically: "works as designed".

The reader returning null actually means: "no more data; I am done here".

See the javadoc:

Returns: A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached

In other words: the socket going closed is seen as "normal" operation here; thus there is no exception. In other words: you have to change your code to check if the result to readLine() returns null; and if so, you know what the socket is gone.

Question:

I am relatively new to socket programming in java and want to send data from a Floatbuffer variable over a tcp socket. This should run on an android platform.

Here's some code to illustrate what I want to do:

FloatBuffer buf = FloatBuffer.allocate(4);
buf.put(5.5f);
buf.put(1.5f);
buf.put(2.5f);
buf.put(3.5f);

ServerSocket server = new ServerSocket(38300);
con = server.accept();

// somehow send the whole buf variable over the tcp socket

I am sure you can extract each float and individually send them over the socket, but I wonder if there is a more efficient way to do so?


Answer:

How about creating a backing ByteBuffer for it. That way you have plenty of choices on how to transmit the data over the network. With a SocketChannel you'll get it as simple as this.

ByteBuffer buf = ByteBuffer.allocate(floats*4);
FloatBuffer floats = buf.asFloatBuffer();
floats.put(5.5f);
...
ServerSocket server = new ServerSocket(38300);
SocketChannel sc = server.accept().getChannel();
sc.write(buf);

Question:

I did an experiment and I created a program with 2 threads: a server thread and a client thread. The server thread accepts a connection from the client, does a long process (emulated by sleep()), and prints the result.

The client on the other hand sends messages really fast.

See the code:

import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

public class SocketTest {

    public static void main(String[] args) throws InterruptedException {
        Thread serverThread = new Thread(() -> server());
        Thread clientThread = new Thread(() -> client());

        serverThread.start();
        clientThread.start();

        serverThread.join();
        clientThread.join();
    }

    private static void server() {
        try (
            ServerSocket listener = new ServerSocket( 1234 );
            Socket client = listener.accept()){  // wait for connection

            while (true) {
                InputStream in = client.getInputStream();

                // read a newline or carriage-return-delimited string
                BufferedReader bin =
                        new BufferedReader( new InputStreamReader( in ) );
                String someString = bin.readLine();
                //process
                Thread.sleep(1000);
                System.out.println(someString);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void client () {
        try (Socket server = new Socket(InetAddress.getLocalHost(), 1234))
        {
            while (true) {
                OutputStream out = server.getOutputStream();

                // write a newline or carriage return delimited string
                PrintWriter pout = new PrintWriter(out, true);
                pout.println("Hello!");

                // send the the string
                pout.flush();
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

When I ran the program I got the following output:

Hello!
Hello!
llo!
o!

ello!
lo!
!
Hello!
llo!
o!

ello!
lo!
!
Hello!
llo!
o!

ello!
lo!
!
Hello!
llo!
o!

ello!
...

Now I am not sure I understand it 100%... But I did run the experiment of using an input the size of a power of 2 (including /n) and the output was not cut off.

Can someone explain to me:

  1. What's going on internally?
  2. Why no error is thrown?
  3. What would you do to overcome this problem?

Thanks!!


Answer:

private static void server() {
    ...
        while (true) {
            InputStream in = client.getInputStream();

            // read a newline or carriage-return-delimited string
            BufferedReader bin =
                    new BufferedReader( new InputStreamReader( in ) );
            String someString = bin.readLine();

This creates a new BufferedReader for each run of while loop. But readline will not only read a line from the socket. It will instead read a larger amount of data, check if there is a line end in it, read more if no line end yet etc and finally return the line. The rest of the read data is kept in the BufferedReader. By implicitly abandoning the BufferedReader at the end of loop run and creating a new one at the beginning of a new loop run you abandon all data in the buffer which were already read from the socket.

Instead you should create your BufferedReader outside the loop and use it there so that no data gets abandoned:

private static void server() {
    ...
        InputStream in = client.getInputStream();
        BufferedReader bin =
                new BufferedReader( new InputStreamReader( in ) );

        while (true) {
            // read a newline or carriage-return-delimited string
            String someString = bin.readLine();

Question:

I wanted to print io.netty.buffer.ByteBuf as string. But io.netty.buffer.ByteBuf.array() throws exception as follows.

java.lang.UnsupportedOperationException: direct buffer at io.netty.buffer.PooledUnsafeDirectByteBuf.array(PooledUnsafeDirectByteBuf.java:343)

Could some one help me to get the byte[] from byte io.netty.buffer.ByteBuf.

Thanks.


Answer:

OK, I have figured out a way to print the values. If anyone is interested,

byte[] bytes = new byte[buf.readableBytes()];
buf.duplicate().readBytes(bytes);
System.out.println(new String(bytes));

Question:

I have been trying to send messages from a server to my application. I am using application "Simple Socket Tester" to create a server and send UTF-8 messages to the application. I never got the messages on my application and when I debugged the app it gets stuck on the line "mServerMessage= mBufferIn.readLine();" and never gets past it. So it seems it is not able to read the message. When I pause the debugger I come to "LocalSocketImpl.java" where it is stuck on "private native FileDescriptor accept". What can I do to prevent this?

My TCP Client:

public TcpClient(OnMessageReceived listener) {
    mMessageListener = listener;

}

/**
 * Sends the message entered by client to the server
 *
 * @param message text entered by client
 */
public void sendMessage(String message) {
    if (mBufferOut != null && !mBufferOut.checkError()) {
        mBufferOut.println(message);
        mBufferOut.flush();
    }
}


/**
 * Close the connection and release the members
 */
public void stopClient() {

    mRun = false;

    if (mBufferOut != null) {
        mBufferOut.flush();
        mBufferOut.close();
    }

    mMessageListener = null;
    mBufferIn = null;
    mBufferOut = null;
    mServerMessage = null;
}

public void run() {

    mRun = true;

    try {
        //here you must put your computer's IP address.
        InetAddress serverAddr = InetAddress.getByName(SERVER_IP);

        Log.e("TCP Client", "C: Connecting...");

        //create a socket to make the connection with the server
        Socket socket = new Socket(serverAddr, SERVER_PORT);

        try {

            //sends the message to the server
            mBufferOut = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
            sendMessage("hi");

            //receives the message which the server sends back
            mBufferIn = new BufferedReader(new InputStreamReader(socket.getInputStream(),"UTF-8"));



            //in this while the client listens for the messages sent by the server
            while (mRun) {

                mServerMessage = mBufferIn.readLine();
                System.out.println(mServerMessage);

                if (mServerMessage != null && mMessageListener != null) {
                    //call the method messageReceived from MyActivity class
                    mMessageListener.messageReceived(mServerMessage);
                }

            }

            Log.e("RESPONSE FROM SERVER", "S: Received Message: '" + mServerMessage + "'");

        } catch (Exception e) {

            Log.e("TCP", "S: Error", e);

        } finally {
            //the socket must be closed. It is not possible to reconnect to this socket
            // after it is closed, which means a new socket instance has to be created.
        }

    } catch (Exception e) {

        Log.e("TCP", "C: Error", e);

    }

}

//Declare the interface. The method messageReceived(String message) will must be implemented in the MyActivity
//class at on asynckTask doInBackground
public interface OnMessageReceived {
    public void messageReceived(String message);
}

}


Answer:

The string that you receive must have '\n' at the end. The readLine method will stop reading or will wait for the stream until it reads a '\n'.

Question:

I'm designing a communications system for my project. However, I'm having some trouble handling packets. My communications system is written in java.net using ServerSocket, Socket, BufferedReader, and PrintWriter.

Currently, my system listens for packets every 500ms. It handles the login packet fine but it fails to handle the post-login packets(send id, disconnection). Every 500ms, I need my server to listen for login and post-login packets(send id, disconnection). How would I design a method that would detect and process post-login packets? The login packet consists of the handshake code, username, and password. Post-login packets (print id, disconnection) consist of the handshake code, user id, event id and other event parameters.

Packets are sent and received as a line of text using bufferedreader and printwriter.

This is my server sided decoder

    protected void decode(Socket server) throws Exception {
    final BufferedReader reader = new BufferedReader(new InputStreamReader(server.getInputStream()));
    final int handshake = Integer.parseInt(reader.readLine());
    if (handshake == LOGIN) {
        final Session session = new LoginSession(server, reader);
        session.read(-1);
    } else if (handshake == POST_LOGIN) {
        final int index = Integer.parseInt(reader.readLine());
        final int opcode = Integer.parseInt(reader.readLine());
        final Session session = store.get(index).getSession();
        session.reader = reader;
        session.read(opcode);
    }

}

@Override
public void run() {
    Socket server;
    try {
        server = serverSocket.accept();
        server.setTcpNoDelay(false);
        decode(server);
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}

These are my client -> server packets

    public void sendLogin() {
    write.write("100");
    write.write('\n');
    write.write("raees2");
    write.write('\n');
    write.write("LOL2");
    write.write('\n');
    write.flush();
}

public void sendPrintId() throws NumberFormatException, IOException {
    final BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
    final int id = Integer.parseInt(reader.readLine());
    System.out.println(id);

    write.write("101");
    write.write('\n');
    write.write(Integer.toString(id));
    write.write('\n');
    write.write(Integer.toString(0));
    write.write('\n');
    write.write(Integer.toString(10003));
    write.write('\n');
    write.flush();
}

public void sendDisconnection() throws NumberFormatException, IOException {
    final BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
    final int id = Integer.parseInt(reader.readLine());
    System.out.println(id);

    write.write("101");
    write.write('\n');
    write.write(Integer.toString(id));
    write.write('\n');
    write.write(Integer.toString(1));
    write.write('\n');
    write.flush();
}

Answer:

Basically, you just need a loop to keep reading from the stream until the conversation is done. Right now, it reads one message and terminates.

I'm not sure how your protocol works, but something like this could give a starting point:

protected void decode(Socket server) throws Exception {
    final BufferedReader reader = new BufferedReader(new InputStreamReader(server.getInputStream()));

    /*
     * Somewhere in this loop, detect your protocol's termination condition
     * and break out.
     */

    for (;;) {
        final int handshake = Integer.parseInt(reader.readLine());
        if (handshake == LOGIN) {
            final Session session = new LoginSession(server, reader);
            session.read(-1);
        } else if (handshake == POST_LOGIN) {
            final int index = Integer.parseInt(reader.readLine());
            final int opcode = Integer.parseInt(reader.readLine());
            final Session session = store.get(index).getSession();
            session.reader = reader;
            session.read(opcode);
        }
    }
}

If you need to handle multiple connections at the same time, you will probably want your acceptor thread to start a new client thread for every connection successfully connected, as decode will block as it waits for the next messages.

Question:

I want to know is there any option to read previously written data to socket when socket get closed due to network loss ?

Although my application is in Java environment, but I want to know answer for general purpose OS behavior. If anyone know in terms of winsocks and unix socket behavior they also welcome.


Answer:

The socket doesn't get closed due to network loss. Only you can close your socket.

The connection can be reset due to network problems.

In this case all pending data is discarded. Nothing you can do about it.

Question:

I made a server and client Java application. They should communicate each other through TCP sockets with Threads. I used InputStreamReader and BufferedReader to read message, and I used OutputStreamWriter and BufferedWriter to write message. The object of BufferedReader is called reader, and the object of BufferedWriter is called writer.

After playing around with that, I realized the socket becomes irresponsive if the writer is closed.

I closed the writer on server side because it will never send any message, but will read message from client only. it does not throw any exception, but stuck where I called any methods relate to socket such as reader.readline() and socket.setSoTimeout().

The problem was easy to solve since I just don't close the writer. However, I am very curious why the socket is being unable to communicate.


Answer:

the socket becomes irresponsive if the writer is closed

The socket becomes closed if the writer is closed.

I closed the writer on server side because it will never send any message,

Non sequitur. If you don't need the Writer, don't construct it.

stuck where I called any methods relate to socket such as reader.readline() and socket.setSoTimeout().

It isn't 'stuck'. It's closed. You must have got SocketException: socket closed when you called either of those methods. You should have noticed that, and you should have posted it in your question.

Question:

String buffer = argv[1] + " " + argv[2] + " " + argv[3];
Socket sock = new Socket(ip, port);
DataOutputStream send = new DataOutputStream(sock.getOutputStream());
BufferedReader recv = new BufferedReader(new InputStreamReader(sock.getInputStream()));
send.writeBytes(buffer + '\n');

String result = recv.readLine();
System.out.println("From Server: " + result);
sock.close();

I have a java TCP client connecting to a server written in C. The client tells the server to multiply/add two numbers and the server sends the result. For some reason when I call readLine() it returns the string sent from the server along with part of the buffer.

For example, I send the server "multiply 10 10", the server sends back "100" and the client prints 100tiply1010. I've already checked that the server is not at fault, and it works fine with a client written in C.

Any idea why this is happening?


Answer:

There is a bug in the server. It is sending back part of the request string in the response string. Possibly it is is null-terminating the response and you're expected to look for the null and ignore everything past it, and presumably the C client does that, but the server shouldn't be sending anything extra in the first place.

In other words the server is probably using sizeof buffer as the length argument to send(), rather than strlen(buffer) or possibly strlen(buffer)+1 if the trailing null is part of the protocol. It all seems to be very poorly defined.

In any case using readLine() on data that isn't line-terminated isn't correct.

Question:

Whenever I try to receive a message from my Server, I get the exception below. This happens at the line rcvdId = inFromServer.readLine(); in the Client. The server does receive the variables I am sending. The variable serialToNucleo.nucleoAnswer even contains a string. I know the code will not fully work yet, as I am only sending one variable, but I am working on that.

Client:

try {

    Socket skt = new Socket("192.168.1.9" , 6789);

    BufferedReader inFromServer = new BufferedReader(new InputStreamReader(skt.getInputStream()));
    PrintWriter out = new PrintWriter(skt.getOutputStream(), true);
    System.out.print("Sending string: '" + vraagTemp + " and " + vraagId+"'\n");
    out.print(vraagTemp + "\n");
    out.print(vraagId + "\n");
    out.close();
    rcvdId = inFromServer.readLine();
    rcvdTemp = inFromServer.readLine();

    WriteToDb writeToDb = new WriteToDb();
    writeToDb.SendDataToDb(rcvdId,rcvdTemp);

    skt.close();

}

Server:

while (true) {

    Socket skt = serverSocket.accept();
    BufferedReader inFromClient = new BufferedReader(new InputStreamReader(skt.getInputStream()));
    PrintWriter out = new PrintWriter(skt.getOutputStream(), true);
    ontvServer = inFromClient.readLine();
    id = inFromClient.readLine();
    System.out.println("Received: " + ontvServer);

    if (id != null && ontvServer != null)
    {
        serialToNucleo.SetupComm(ontvServer, id);
    }
    else
    {
        Thread.sleep(100);
    }

    if (serialToNucleo.nucleoAnswer!= null) {
        out.print(serialToNucleo.nucleoAnswer + "\n");
        id = null;
        ontvServer = null;
    }
    else
    {
        Thread.sleep(100);
    }

}

Stacktrace from the exception thrown

java.net.SocketException: socket closed at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at ChatClient.main(ChatClient.java:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

Answer:

'Socket closed' means that you closed the socket and then continued to use it.

It has nothing to do with 'connection lost'.

It happens here:

out.close();

Closing either the input or output stream of a socket closes the socket. Change to out.flush().

NB Your server code leaks sockets like a sieve.