【问题标题】:Socket intermittently reads only 1448/2896 bytes套接字间歇性地仅读取 1448/2896 字节
【发布时间】:2018-04-10 11:37:09
【问题描述】:

我正在使用 Commons-IO 从 Socket 读取和写入。一切正常,直到有效载荷大小达到最大值 1448/2896。

下面是代码sn-p。真的不知道怎么处理。 也检查了系统缓冲区大小

$ cat /proc/sys/net/ipv4/tcp_wmem
4096    16384   4194304
public static void usingCommonsIO(){
    Socket socket = null;
    try {
        socket = new Socket(serverIP, 55000);
        IOUtils.write(request.getBytes(), socket.getOutputStream());
        System.out.println("Message Sent....");
        StringBuilder response = new StringBuilder();
        String resp =IOUtils.toString(socket.getInputStream(), "UTF-8");
        System.out.println(resp);
    } catch (IOException e) {
        e.printStackTrace();
    }

}

另外尝试使用 DataInputStream 但没有运气。截取的代码如下。

public static void usingDataIOStream(String requestStr){
    Socket socket = null;
    try {
        socket = new Socket("192.168.1.6", 55000);
        System.out.println("Request Length -:" + request.length());
        DataOutputStream out = new DataOutputStream(socket.getOutputStream());
        out.write(requestStr.getBytes("UTF-8"), 0, requestStr.length());
        out.flush();
        System.out.println("Message Sent....");
        DataInputStream din = new DataInputStream(socket.getInputStream());
        byte[] response = new byte[16*1024];
        int responseLength = din.read(response);
        System.out.println("Response -:" + new java.lang.String(response, 0, responseLength));

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

}

令人困惑的部分是相同的代码有时仅使用 1448 字节,有时最多使用 2896 字节。没有特定的模式。

更新 1

为了模拟它,我尝试自己编写服务器套接字,代码如下。注意到这一点的奇怪事情是,在第一次请求时,大小为 6500 的有效负载被正确读取和接收。从第二个请求开始连接重置。我在这里遗漏了什么吗?

public static void usingBAOS() throws IOException {

    server = new ServerSocket(port);
    Socket socket = null;
    DataInputStream din = null;
    DataOutputStream dos = null;
    while (true) {
        System.out.println("Waiting  for Client...");
        try {
            // Accepting Client's connection
            socket = server.accept();
            System.out.println("Connnected to client " + socket.getInetAddress());
            din = new DataInputStream(socket.getInputStream());
            // Read request payload from Socket
            String requestString = readRequest(din);
            System.out.println("Request Read.....");
            System.out.println("Writing Response.....");
            // Writing response to socket
            dos = writeResponse(socket, requestString);

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //close resources
            din.close();
            System.out.println("InputStream is closed......");
            dos.close();
            System.out.println("OutputStream is closed......");
            socket.close();
            System.out.println("Socket is closed......");
        }
    }
}

private static DataOutputStream writeResponse(Socket socket, String requestString) throws IOException {
    String responseString = "Hi Client" + requestString;

    DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
    //write object to Socket
    dos.write(responseString.getBytes(),0, responseString.getBytes().length);
    dos.flush();
    return dos;
}

private static String readRequest(DataInputStream din) throws IOException {
    byte[] response = new byte[16*1024];
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    int n = 0;
    boolean read = true;
    while(read){
        n = din.read(response);
        baos.write(response, 0, n);
        if(baos.toString().length() == n){
            read = false;
        }
    }
    baos.flush();
    String requestString = baos.toString();
    return requestString;
}

【问题讨论】:

  • 您使用DataInputStream 的代码是错误的。不能保证单个 read(byte[]) 会读取所有数据。返回值表示读取了多少字节。
  • @Kayaman 感谢您的意见。试过但没有用。 ByteArrayOutputStream baos = new ByteArrayOutputStream();诠释 n = 0; while((n = din.read(response) )!= -1){ baos.write(response, 0, n); }
  • 你的意思是你有同样的行为?会不会是服务器端的问题?你在其他电脑上试过吗?
  • 是的,仍然是相同的行为。这是第三方服务。怀疑是服务器端的问题,但他们声称其他客户端能够消费而没有任何此类问题。
  • 这个问题有两个问题:1)你正在实现一个协议,但你还没有为它提供一个规范。我们必须从您的代码中推断出协议,但这显然无助于诊断不正确的实现; 2)你从不说问题是什么。你暗示出了什么问题,但不知道那是什么。

标签: java sockets datainputstream apache-commons-io


【解决方案1】:

尽管在撰写此答案时这个问题已经过时了,但我将其放在这里以供其他人使用,以防万一它解决了他们的问题。在我天真地假设这样做的 Android 8.0 设备上使用缓冲数据输入和输出流时,我遇到了同样的问题:

int len = 2304;
byte[] data = new byte[len];
inputStream.read(data, 0, len);

将读取我通过套接字发送的所有数据。但是正如@Kayaman 在 cmets 中所建议的那样,即使有可用的字节,这也不能保证实际上从缓冲区中读取了 len 字节的数据。其实这是在documentation:

public final int read(byte[] b, int off, int len) throws IOException

从包含的输入流中读取最多 len 字节的数据到字节数组中。尝试读取多达 len 个字节,但可能会读取较小的字节数,可能为零。实际读取的字节数以整数形式返回。

实际上,如果它没有读取所有数据,唯一的判断方法是捕获返回值。然后我的解决方案是监控从流中实际读取的字节数,然后在循环中调用read():

int i = 0;
len = 2304;
byte[] data = new byte[len];
while (i < len)
{
    i += socket.inputStream.read(data, i, len - i);
}

希望这对某人有所帮助。

【讨论】:

    猜你喜欢
    • 2015-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-25
    • 2016-09-24
    • 1970-01-01
    相关资源
    最近更新 更多