缺少bufferedreader

时间:2017-03-05 14:55:39

标签: java android sockets client-server

我有一个Android设备和一个服务器。服务器可以发送消息告知设备与wifi断开连接。为了快速了解它是如何做到的,这里是一个psudo序列图:

Pseudo sd

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

此处显示了示例循环,从服务器端看到:

     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.");
}

和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;
    }

}

有谁能告诉我,我做错了什么?为什么断开/重新连接后收到的消息 - 双方的新套接字都无法传输整个消息?

编辑:

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

编辑II

尝试:

 DataOutputStream outToServer = null;
BufferedReader inFromClient = null;

并且仅在它们为空时创建它们。当套接字关闭时,这些设置为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

编辑III 通过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�������

1 个答案:

答案 0 :(得分:0)

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

虽然这很有效,但是当TCP-Retransmission发生时,不知怎的,它在重新传输的包上得到了错误的大小。对于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");

    }

}

现在一切正常 - 也在重传期间。 如果有人能告诉我为什么这是有效的,我真的很感激!