qvpham
qvpham

Reputation: 1938

Socket client: don't get the full response with DataInputStream.readUTF()

I want to write a socket client to send a request to a server and get response back. It works, but not right. Here is my code:

public String send(final String data) {
        Socket client = null;
        String response = null;

        try {
            client = new Socket(this.host, this.port);

            final OutputStream outToServer = client.getOutputStream();
            final DataOutputStream out = new DataOutputStream(outToServer);
            out.writeUTF(data);

            final InputStream inFromServer = client.getInputStream();
            final DataInputStream in = new DataInputStream(inFromServer);
            response = in.readUTF();
        } catch (final IOException e) {
            this.log.error(e);
            this.log.error("Sending message to server " + this.host + ":" + this.port + " fail", e);
        } finally {
            if (client != null) {
                try {
                    client.close();
                } catch (final IOException e) {
                    this.log.error("Can't close socket connection to " + this.host + ":" + this.port, e);
                }
            }
        }
        if (StringUtils.isBlank(response)) return null;
        return response;
    }

The problem is: I didn't got the full response with in.readUTF(). I always got a response with the same length as the sent data's length (variable data). I have tested with other GUI client and got the full response. So it's not a problem of the server. Does someone known, what i did wrong?

UPDATE

Thanks EJP and Andrey Lebedenko. I think, my problems are the functions writeUTF and readUTF. So i have edited my code in the try block so:

        Charset charset = Charset.forName("ISO-8859-1");
        final OutputStream outToServer = client.getOutputStream();
        final DataOutputStream out = new DataOutputStream(outToServer);
        out.write(data.getBytes(charset));

        final InputStream inFromServer = client.getInputStream();
        final BufferedReader in = new BufferedReader(new InputStreamReader(inFromServer, charset));
        response = in.readLine();

And it worked now.

Upvotes: 0

Views: 5956

Answers (2)

Andrey Lebedenko
Andrey Lebedenko

Reputation: 1988

Without knowing what does server part do, it is kind of difficult (if possible at all) to trace down the root cause. So in the most honest hope that it will help I just share this code with which I've tested the fragment above.

package tcpsendreceive;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;

public class SendReceive {
    private static final Logger log = Logger.getLogger(SendReceive.class.toString());

    private final String host;
    private final int port;

    private Server server;

    class Server extends Thread
    {
        private final ServerSocket serverSocket;
        public Server(ServerSocket s)
        {
            serverSocket = s;
        }

        @Override
        public void run()
        {
            Socket connection;
            SendReceive.this.log.log(Level.INFO, "Server: DoubleEcho Server running on "+this.serverSocket.getLocalPort());
            try{
                do {
                    connection = this.serverSocket.accept();
                    SendReceive.this.log.log(Level.INFO, "Server: new connection from "+connection.getRemoteSocketAddress());
                    int b;
                    do {
                        DataInputStream in = new DataInputStream(connection.getInputStream());
                        String s = in.readUTF();

                        DataOutputStream out = new DataOutputStream(connection.getOutputStream());
                        out.writeUTF(s+","+s); // echo it back TWICE

                        out.flush();
                        connection.shutdownOutput();
                        connection.close();
                    } while(!connection.isClosed());
                }
                while(true);
            }
            catch(IOException ioe)
            {
                SendReceive.this.log.log(Level.SEVERE, "IOException in server! - STOP", ioe);
            }
            finally {
                try{
                    this.serverSocket.close();
                } catch (Exception e) {
                    SendReceive.this.log.log(Level.SEVERE, "IOException closing server! - FATAL", e);
                }
                try{
                    if(!connection.isClosed())
                      connection.close();
                } catch (Exception e) {
                    SendReceive.this.log.log(Level.SEVERE, "IOException closing server! - FATAL", e);
                }
            }
        }
    }

    public SendReceive(String host, int port)
    {
        this.host = host;
        this.port = port;
        try{
            this.server = new Server(new ServerSocket(this.port));
            this.server.start();
        }
        catch(IOException ioe)
        {
            this.log.log(Level.SEVERE, "IOException while creating server! - STOP", ioe);
        }
    }

    public String send(final String data) {
        Socket client = null;
        String response = null;

        try {
            client = new Socket(this.host, this.port);

            final OutputStream outToServer = client.getOutputStream();
            final DataOutputStream out = new DataOutputStream(outToServer);
            out.writeUTF(data);

            final InputStream inFromServer = client.getInputStream();
            final DataInputStream in = new DataInputStream(inFromServer);
            response = in.readUTF();
        } catch (final IOException e) {
            this.log.log(Level.SEVERE, "Sending message to server " + this.host + ":" + this.port + " fail", e);
        } finally {
            if (client != null) {
                try {
                    client.close();
                } catch (final IOException e) {
                    this.log.log(Level.SEVERE, "Can't close socket connection to " + this.host + ":" + this.port, e);
                }
            }
        }
        if(response == null || response.isEmpty()) 
            return null;

        return response;
    }    
}

Test-demo

package tcpsendreceive;

public class Main {
    public static void main(String[]  args)
    {    
        String data = "AAABBB";
        SendReceive sr = new SendReceive("localhost", 5000);
        String res = sr.send(data);
        System.out.println("Sent: "+data);
        System.out.println("Received: "+res);
    }
}

Result (key part):

Sent: AAABBB
Received: AAABBB,AAABBB

Hope it helps.

EDIT 1. Corrected wrapper flush instead of socket stream flush. Still believe it is good practice to flush the stream wrapper before closing the socket.

  1. Client socket closed in IOException block (since they aren't automatically closed on ServerSocket shutdown). Thanks @EJP

P.s. I should admit I was bit surprised by such an attention to the humble test server code, especially compared to other dirty tests we all have seen on SO. Flattered. :)

Upvotes: 0

user207421
user207421

Reputation: 310957

If it works with Telnet, as per your comment, the server isn't using readUTF(), so your writeUTF() is already wrong, and the server is therefore unlikely to be using writeUTF() either, which would make your readUTF() wrong as well. You can't use these methods arbitrarily: they can only interchange data between themselves.

I'll bet your GUI client that works doesn't use them either.

Upvotes: 1

Related Questions