【问题标题】:Better way to communicate between TCP Client and ServerTCP客户端和服务器之间更好的通信方式
【发布时间】:2020-03-31 07:06:19
【问题描述】:

我有一个命令系统在我的 TCP 服务器和客户端 (Java) 之间进行通信。我可以向我的客户端发送特定的命令,如果客户端收到命令,它将执行某些操作。

基本上,这行得通。但有时我必须发送命令 + 额外信息。问题是:信息有时会发送得太快。所以一些信息会丢失/混淆,我的客户无法正确执行请求。 我的解决方案是使用Thread.sleep(),但这既不干净也不高效。因为仍然存在无法正确接收信息的风险。

我的服务器:

public void sendCommand(Socket socket) throws InterruptedException, IOException {
    writeMsg("CMD_POPUP", socket);
    Thread.sleep(150);
    writeMsg("foo", socket);
    Thread.sleep(150);
    writeMsg("bar", socket);
    Thread.sleep(150);
    writeMsg("baz", socket);
}

public void writeMsg(String message, Socket socket) throws IOException {
    DataOutputStream out = new DataOutputStream(socket.getOutputStream());
    out.writeUTF(message);
}

我的客户:

public void interpreteCommand(Socket socket) throws IOException {
    while (true) {
        switch (readMsg(socket)) {
            case "CMD_POPUP":
                System.out.println(readMsg(socket)); 
                System.out.println(readMsg(socket)); //Sometimes it would be 'bar' but also sometimes it would be 'baz'
                System.out.println(readMsg(socket)); //Sometimes it would be 'baz' but also sometimes it would be nothing
                break;
        }
    }
}

public String readMsg(Socket socket) throws IOException {
    DataInputStream in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
    return in.readUTF();
}

【问题讨论】:

    标签: java sockets networking tcp


    【解决方案1】:

    首先,我不是java程序员。但是 tcp 连接在其他编程语言中的工作方式相同。

    TCP 连接是基于流的,这意味着消息没有开始或结束。 TCP 唯一能保证的是数据以正确的顺序到达。

    如果你紧接着发送“CMD_POPUP”和“foo”,你不知道对方是否会收到“CMD_POPUP”、“CMD_POPUPfoo”、“CMD_PO”等。因为您在每次发送之间等待特定的时间,所以数据通常一个接一个地到达。但这并不能保证,我也认为这是一种不太干净的方式。

    解决这个问题的最简单方法是在开头发送一个开始字符,在参数之间发送分隔符,在每条消息之后发送一个结束字符。 例如"#CMD_POPUP%foo%bar$" 之类的。这样,您可以将收到的所有内容写入缓冲区,直到收到消息的结尾,然后再对其进行处理。

    【讨论】:

    • “TCP 唯一能保证的是数据以正确的顺序到达。” - 实际上,不止于此:它完全到达 并且它的所有部分都按正确的顺序。
    • “解决这个问题的最简单方法是在开头发送一个起始字符...” = 实现某种应用协议。
    【解决方案2】:

    实际上,您不需要Thread.sleep,而是可以传递附加在命令本身的额外信息,例如writeMsg("foo;extrainformation", socket);,然后在第一部分是命令的地方拆分此字符串。

    否则,您可以传递整个 objectjson 结构,而不是传递 string,以便更好地实现。

    【讨论】:

      猜你喜欢
      • 2014-05-10
      • 1970-01-01
      • 2012-04-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多