bufferedreader 中缺少第一个字符

Missing first char in bufferedreader

我有一个 android 设备和一个服务器。服务器可以传输一条消息,告诉设备断开与 wifi 的连接。为了快速了解它是如何做到的,这里有一个伪序列图:

现在有趣的是,当客户端重新连接时,服务器传输一条消息,有时该消息缺少第一个字符,有时是下一条消息。尽管如此,它在客户端重新连接后很快就会发生。

这里显示了示例循环,从服务器端看:

     while (true) {
        server_.transmitMessage("SLAVE", "WIFI");
        Thread.sleep(40000);
        System.out.println("Should be back");
        server_.transmitMessage("SLAVE", "Hi wififims");
        Thread.sleep(5000);
    }

Android-设备的输出:

03-05 15:36:01.200 17152-17180/com.example.bla.psedowifidims I/System.out: Conecting to 192.168.1.77:6650
03-05 15:36:11.080 17152-17181/com.example.bla.psedowifidims I/System.out: Received: WIFI
03-05 15:36:11.080 17152-17181/com.example.bla.psedowifidims I/System.out: Client expecting disconnect.
03-05 15:36:11.080 17152-17181/com.example.bla.psedowifidims I/System.out: Expecting disconnect.
03-05 15:36:11.590 17152-17181/com.example.bla.psedowifidims I/System.out: Killing wifi
03-05 15:36:16.660 17152-17181/com.example.bla.psedowifidims I/System.out: Enableing wifi
03-05 15:36:31.760 17152-17181/com.example.bla.psedowifidims I/System.out: Conecting to 192.168.1.77:6650
03-05 15:36:51.550 17152-17181/com.example.bla.psedowifidims I/System.out: Received: Hi wififims
03-05 15:36:56.780 17152-17181/com.example.bla.psedowifidims I/System.out: Received: IFI

如最后一行所示,重新连接后发送的第二条消息在接收时存在缺陷。应该是"WIFI"。如果我让程序 运行 一段时间,比方说 5 分钟,突然丢失的字符带有另一条消息:

03-05 15:52:32.480 17152-17181/com.example.bla.psedowifidims I/System.out: Received: WWWWWWWWWWWWIFI

服务器

这里显示的是监听服务器:

    public void startListening(int port) {
    this.port = port;
    canceled_ = false;
    new Thread(() -> {
        try {
            System.out.println("Listening for incomming connections on port " + port);
            serverSocket_ = new ServerSocket(port);
            while (!canceled_) {
                ServerClient serverClient = new ServerClient(serverSocket_.accept(), networkReceiver, server_);
                serverClient.listen();
                serverClient.setIdWithoutTransmission(Long.toString(clientId++));
                this.ServerClientList_.add(serverClient);
                networkReceiver.onNewClient(serverClient.getId());
                System.out.println("Client connected from:" + serverClient.getClientSocket().getInetAddress() +
                                           serverClient.getClientSocket().getPort());
            }

        } catch (IOException e) {
            handleDisconnect();
        }
    }).start();
}

这将本地 ServerClient 设置为侦听状态:

  public void listen() {
    this.canceled_ = false;
    new Thread(() -> {
        while (!canceled_) {
            try {
                if (clientSocket_ == null) {
                    System.out.println("Socket is null, returning from listening");
                    return;
                }
                clientSocket_.setSoTimeout(0);
                BufferedReader inFromClient = new BufferedReader(new InputStreamReader(clientSocket_
                                                                                               .getInputStream()));
                String msg = inFromClient.readLine();
                if (msg == null) {
                    super.handleDisconnect();
                    return;
                }
                if (handleMessage(msg))
                    continue;
                networkReceiver.onNewMessage(msg);
            } catch (IOException e) {
                super.handleDisconnect();
            }
        }
    }).start();

}

当服务器向客户端传输时:

    public void transmitMessage(String id, String msg) {
    for (ServerClient ServerClient : ServerClientList_) {
        System.out.println("Does  " + id + " equals "+ ServerClient.getId());
        if (ServerClient.getId().equals(id)) {
            ServerClient.transmitMessage(msg);
            return;
        }
    }
    System.out.println("Couldn't find ServerClient.");
}

和服务器客户端的实际方法:

    public void transmitMessage(String message) {
    if (clientSocket_ == null || !clientSocket_.isBound()) {
        System.out.println("Not connected, can't transmit. Make sure you are connected to the host\nClientsocket " +
                                   "is null or not bound");
        return;
    }

    DataOutputStream outToServer = null;
    try {
        outToServer = new DataOutputStream(clientSocket_.getOutputStream());
        outToServer.writeBytes(message + '\n');
    } catch (IOException e) {
        System.out.println("Error while writing to socket - message not delivered");

    }

}

处理服务器上的断开连接(客户端发送已处理的消息)。

 private boolean handleMessage(final String msg) {
    if (msg.equals(EXPECT_DISCONNECT_MSG)) {
        EXPECT_DISCONNECT_FLAG(true);
        return true;
    }

然后当 ServerClients 侦听器捕获到异常时,它会看到已升起的标志,并调用:

    protected void handleExpectedDisconnect() {
    server_.lossOfClient(this);
    this.canceled_ = true;
    finalizeSockets();
}

lossOfClient 很简单:

    public void lossOfClient(final ServerClient serverClient) {
    this.ServerClientList_.remove(serverClient);
    System.out.println("Removed client with ID " + serverClient.getId());
    System.out.println("Size: " + server_.getServerClientList().size());
}

客户端

客户端初始化为

    public void connectAndListen(String host, int port) {
    this.canceled_ = false;
    try {
        System.out.println("Conecting to " + host + ":" + port);
        clientSocket_ = new Socket(host, port);
        clientSocket_.setSoTimeout(2000);
        listen();
    } catch (IOException e) {
        System.out.println("Socket error - restarting");
    }

}

   public void listen() {
    this.canceled_ = false;
    new Thread(() -> {
        while (!canceled_) {
            try {
                if (clientSocket_ == null) {
                    System.out.println("Socket is null, returning from listening");
                    return;
                }
                clientSocket_.setSoTimeout(0);
                BufferedReader inFromClient = new BufferedReader(new InputStreamReader(clientSocket_
                                                                                               .getInputStream()));
                String msg = inFromClient.readLine();
                if (msg == null) {
                    super.handleDisconnect();
                    return;
                }
                if (handleMessage(msg))
                    continue;
                networkReceiver.onNewMessage(msg);
            } catch (IOException e) {
                super.handleDisconnect();
            }
        }
    }).start();

}

断开连接:

   public void disconnect() {
    try {
        if (clientSocket_ != null && clientSocket_.isBound()) {
            System.out.println("Client expecting disconnect.");
            EXPECT_DISCONNECT_FLAG(true);
            transmitMessage(EXPECT_DISCONNECT_MSG);
            Thread.sleep(500);
        }
        finalizeSockets();
    } catch (InterruptedException e) {
        System.out.println("Coudln't inform receiver about expected disconnect."); 

    }
}

    public void finalizeSockets() {
    if (clientSocket_ != null && clientSocket_.isBound()) {
        try {
            if (!clientSocket_.isClosed())
                clientSocket_.close();
        } catch (IOException e) {
            System.out.println("Couldn't close clientsocket");
        }
        clientSocket_ = null;
    }

}

谁能告诉我,我做错了什么?为什么在 disconnect/reconnect 之后收到的消息 - 这是双方的新套接字,无法传输整个消息?

编辑:

尝试刷新输出流,以确保所有字节都已发送,但没有帮助。 最好的问候。

编辑二

尝试过:

 DataOutputStream outToServer = null;
BufferedReader inFromClient = null;

并且只在它们为空时创建它们。当套接字关闭时,这些设置为空。同样的问题:

03-05 18:05:00.000 11383-11427/com.example.bla.psedowifidims I/System.out: 

Conecting to 192.168.1.77:6650
03-05 18:05:06.470 11383-11428/com.example.bla.psedowifidims I/System.out: Received: Hi wififims
03-05 18:05:11.490 11383-11428/com.example.bla.psedowifidims I/System.out: Received: WIFI
03-05 18:05:11.490 11383-11428/com.example.bla.psedowifidims I/System.out: Client expecting disconnect.
03-05 18:05:11.490 11383-11428/com.example.bla.psedowifidims I/System.out: Expecting disconnect.
03-05 18:05:12.000 11383-11428/com.example.bla.psedowifidims I/System.out: Killing wifi
03-05 18:05:17.090 11383-11428/com.example.bla.psedowifidims I/System.out: Enableing wifi
03-05 18:05:32.180 11383-11428/com.example.bla.psedowifidims I/System.out: Conecting to 192.168.1.77:6650
03-05 18:05:51.530 11383-13368/com.example.bla.psedowifidims I/System.out: Received: i wififims
03-05 18:05:56.560 11383-13368/com.example.bla.psedowifidims I/System.out: Received: IFI
03-05 18:06:38.300 11383-11428/com.example.bla.psedowifidims I/System.out: Received: HWHi wififims
03-05 18:06:43.340 11383-13368/com.example.bla.psedowifidims I/System.out: Received: WIFI

编辑三 通过 wireshark 跟踪,我可以看到有时像 "WIFI" 这样的消息被分成两个包,一个是 W,另一个是 IFI。好像是这个原因,所以我试了一下:

public void listen(){
    ....
            byte[] arbytes = new byte[inFromServer.readInt()];
            int length = arbytes.length;
            inFromServer.read(arbytes,0,length);
....
}

并在传输中

public void transmitMessage(String message) {

....
    try {
        if(outToServer == null)
            outToServer = new DataOutputStream(clientSocket_.getOutputStream());

        byte[] databyes = message.getBytes(Charset.forName("UTF-8"));
        outToServer.writeInt(databyes.length);
        outToServer.write(databyes);

    } catch (IOException e) {
        System.out.println("Error while writing to socket - message not delivered");

    }

}

虽然还是没有运气:

03-05 20:01:10.810 27328-27353/com.example.bla.psedowifidims I/System.out: 

Conecting to 192.168.1.77:6650
03-05 20:01:21.600 27328-27354/com.example.bla.psedowifidims I/System.out: Received: WIFI
03-05 20:01:21.600 27328-27354/com.example.bla.psedowifidims I/System.out: Client expecting disconnect.
03-05 20:01:21.600 27328-27354/com.example.bla.psedowifidims I/System.out: Expecting disconnect.
03-05 20:01:22.110 27328-27354/com.example.bla.psedowifidims I/System.out: Killing wifi
03-05 20:01:27.200 27328-27354/com.example.bla.psedowifidims I/System.out: Enableing wifi
03-05 20:01:42.270 27328-27354/com.example.bla.psedowifidims I/System.out: Conecting to 192.168.1.77:6650
03-05 20:01:42.290 27328-27354/com.example.bla.psedowifidims I/System.out: Percent bad: 0.0
03-05 20:02:01.560 27328-28467/com.example.bla.psedowifidims I/System.out: Received: ififims�������

好吧 - 我经历了很多考验。我尝试手动发送要传输的 og 字节数,然后是数据,然后在客户端进行相应的操作。

虽然这有效,但当发生 TCP 重传时,重传包的大小不知何故错误。这与 WriteUTF 等相同。

不知何故 - 经过多次尝试,我将传输器更改为使用 PrintWriter。

    public void transmitMessage(String message) {
    if (clientSocket_ == null || !clientSocket_.isBound()) {
        System.out.println("Not connected, can't transmit. Make sure you are connected to the host\nClientsocket " +
                "is null or not bound");
        return;
    }

    try {
        if (outToServer == null)
            outToServer = new DataOutputStream(clientSocket_.getOutputStream());


        PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(clientSocket_.getOutputStream())), true);
        pw.println(message);
        pw.flush();

    } catch (IOException e) {
        System.out.println("Error while writing to socket - message not delivered");

    }

}

现在一切正常 - 在重新传输期间也是如此。 如果有人能告诉我为什么 这行得通,我将不胜感激!