简体   繁体   English

套接字客户端:不要通过DataInputStream.readUTF()获得完整的响应

[英]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() . 问题是:我没有收到in.readUTF()的完整答复。 I always got a response with the same length as the sent data's length (variable data ). 我总是得到与发送数据长度相同的响应(可变data )。 I have tested with other GUI client and got the full response. 我已经使用其他GUI客户端进行了测试,并获得了完整的响应。 So it's not a problem of the server. 因此,这不是服务器的问题。 Does someone known, what i did wrong? 有人知道我做错了吗?

UPDATE 更新

Thanks EJP and Andrey Lebedenko. 感谢EJP和Andrey Lebedenko。 I think, my problems are the functions writeUTF and readUTF . 我认为,我的问题是函数writeUTFreadUTF So i have edited my code in the try block so: 所以我在try块中编辑了我的代码,因此:

        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. 现在就可以了。

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. 如果它可以与Telnet配合使用(如您的评论所述),则服务器未使用readUTF() ,因此您的writeUTF()已经错误,因此服务器也不太可能使用writeUTF() ,这会使您的readUTF()错误的。 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. 我敢打赌,您的GUI客户端也不会使用它们。

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. 编辑 1.更正了包装刷新,而不是套接字流刷新。 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). 客户端套接字在IOException块中关闭(因为它们不会在ServerSocket关闭时自动关闭)。 Thanks @EJP 谢谢@EJP

Ps 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. 附言:我应该承认,对如此不起眼的测试服务器代码的关注让我感到惊讶,特别是与我们在SO上看到的其他肮脏测试相比。 Flattered. 受宠若惊。 :) :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM