繁体   English   中英

Java通过TCP Socket分别发送数据

[英]Java send data over TCP Socket seperately

我想在 Java 中使用 tcp 套接字分别发送多个数据包。 这是我的代码。

try {
    DataOutputStream out = new DataOutputStream(socket.getOutputStream());
    String[] array = new String[4];
    array[0] = "stack";
    array[1] = "over";
    array[2] = "flow";
    array[3] = "coding";
    for (int i = 0; i < array.length; i++) {
        out.write(array[i].getBytes()); //send packet
    }
} catch (IOException e) {
    throw new RuntimeException(e);
}

我现在把所有数据都放在一个数据包中。 这是接收到的数据包的终端输出:

Incoming Transmission => stackoverflowcoding

这就是我想要的:

Incoming Transmission => stack
Incoming Transmission => over
Incoming Transmission => flow
Incoming Transmission => coding 

如何分别接收 4 个数据包的数据?

我为什么要这个? 因为在我的客户中有一个监听即将到来的 tcp 包的事件。 必须为数组的每个元素分别触发此事件。

TCP 在逻辑上表示一个连续的流,类似于一个文件。 将其视为一个连续的字节序列,直到某个时间点关闭并且流结束。 但是这些字节中的任何两个之间都没有明确的界限。 有时您可能不得不等待获取更多字节,但没有内在的方法可以判断这是因为对方停止发送还是你们两个之间存在某种网络问题。

虽然数据包被用作底层机制,但您不应依赖它们的分离,因为理论上它们可以沿途拆分和合并(实际上它们大多只是拆分而很少合并)。

通常的解决方案是在 TCP 之上使用某种协议来清楚地标记您感兴趣的不同块。最简单的此类协议将简单地从发送下一个块将长的字节数开始,然后是任何数据是。

或者,您可以切换到 UDP,它实际上是基于数据包的,并保证如果您收到某些东西,它将是来自另一端的单个数据包(尽管它不保证数据包的顺序甚至它们的传递)。

可以通过在代码中策略性地放置out.flush()来完成这项工作,但取决于这将使您的代码非常脆弱。

TCP 是一个字节流,它没有消息边界的概念(例如,UDP 就是这样)。 发送和读取之间没有一对一的关系。 发送的数据可以在网络认为有效传输所需的任何数据包中加入和分段。 TCP 为您提供的唯一保证是:

  • 数据将被传递(除非连接关闭或丢失)
  • 数据将按照发送的顺序接收

因此,要执行您的要求,您必须明确标记一个数据的结束位置和下一个数据的开始位置。 例如,通过在实际数据之前发送数据的长度,例如:

try {
    DataOutputStream out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
    String[] array = new String[4];
    array[0] = "stack";
    array[1] = "over";
    array[2] = "flow";
    array[3] = "coding";
    out.writeInt(array.length);
    for (int i = 0; i < array.length; i++) {
        byte[] bytes = array[i].getBytes(StandardCharsets.UTF_8);
        out.writeInt(bytes.length);
        out.write(bytes, 0, bytes.length);
    }
    out.flush();
} catch (IOException e) {
    throw new RuntimeException(e);
}

这样,接收者可以首先读取一个整数以了解正在发送多少个字符串,然后运行一个循环,其中每次迭代读取字符串长度的整数,然后读取该字符串的字节,例如:

try {
    DataInputStream in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
    int count = in.readInt();
    for (int i = 0; i < count; i++) {
        int length = in.readInt();
        byte[] bytes = new byte[length];
        in.readFully(bytes);
        String s = new String(bytes, StandardCharsets.UTF_8);
        System.out.println("Incoming Transmission => " + s);
    }
} catch (IOException e) {
    throw new RuntimeException(e);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM