java - TCP客户端和服务器之间更好的通信方式
问题描述
我有一个命令系统来在我的 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程序员。但是 tcp 连接在其他编程语言中的工作方式相同。
TCP 连接是基于流的,这意味着消息没有开始或结束。TCP 唯一能保证的是数据以正确的顺序到达。
如果你紧接着发送“CMD_POPUP”和“foo”,不知道对方是否会收到“CMD_POPUP”、“CMD_POPUPfoo”、“CMD_PO”等。因为您在每次发送之间等待特定的时间,所以数据通常一个接一个地到达。但这并不能保证,我也认为这是一种不太干净的方法。
解决这个问题的最简单方法是在开头发送一个开始字符,在参数之间发送分隔符,在每条消息之后发送一个结束字符。例如“#CMD_POPUP%foo%bar$”或类似的东西。这样,您可以将收到的所有内容写入缓冲区,直到收到消息的结尾,然后处理它。