简体   繁体   English

Java通过TCP Socket分别发送数据

[英]Java send data over TCP Socket seperately

I want to send multiple packets separately with using tcp socket in Java.我想在 Java 中使用 tcp 套接字分别发送多个数据包。 Here's my code.这是我的代码。

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

I take all data in one packet right now.我现在把所有数据都放在一个数据包中。 Here is the received packet's terminal output:这是接收到的数据包的终端输出:

Incoming Transmission => stackoverflowcoding

That's what i want:这就是我想要的:

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

How can i receive data as 4 packets separately?如何分别接收 4 个数据包的数据?

Why do i want this ?我为什么要这个? Because in my client there's an event that listens the coming tcp packages.因为在我的客户中有一个监听即将到来的 tcp 包的事件。 This event must be triggered for each elements of array separately.必须为数组的每个元素分别触发此事件。

TCP logically represents a continuous stream, similar to a file. TCP 在逻辑上表示一个连续的流,类似于一个文件。 Think of it as one continuous sequence of bytes until at some point in time it's closed and the stream ends.将其视为一个连续的字节序列,直到某个时间点关闭并且流结束。 But there's no definite clear boundary between any two of those bytes.但是这些字节中的任何两个之间都没有明确的界限。 Sometimes you might have to wait to get more bytes, but there's no intrinsic way to tell if that's because the other side stopped sending or if there's some kind of network issue between the two of you.有时您可能不得不等待获取更多字节,但没有内在的方法可以判断这是因为对方停止发送还是你们两个之间存在某种网络问题。

While packets are used as an underlying mechanism you shouldn't rely on their separation, because they could in theory be split and merged along the way (realistically they are mostly just split and rarely merged).虽然数据包被用作底层机制,但您不应依赖它们的分离,因为理论上它们可以沿途拆分和合并(实际上它们大多只是拆分而很少合并)。

The usual solution is to use some kind of protocol on top of TCP to clearly mark the different chunks you're intrested in. The simplest such protocol would simply start by sending the amount of bytes the next chunk will be long, followed with whatever the data is.通常的解决方案是在 TCP 之上使用某种协议来清楚地标记您感兴趣的不同块。最简单的此类协议将简单地从发送下一个块将长的字节数开始,然后是任何数据是。

Alternatively, you could switch to UDP, which is actually packet-based and guarantees that if you receive something it'll be a single packet from the other side (though it doesn't guarantee order of packets or even their delivery).或者,您可以切换到 UDP,它实际上是基于数据包的,并保证如果您收到某些东西,它将是来自另一端的单个数据包(尽管它不保证数据包的顺序甚至它们的传递)。

You might be able to make this work by strategically placing out.flush() in your code, but depending on that will make your code very fragile.可以通过在代码中策略性地放置out.flush()来完成这项工作,但取决于这将使您的代码非常脆弱。

TCP is a stream of bytes, it has no concept of message boundaries (like UDP does, for instance). TCP 是一个字节流,它没有消息边界的概念(例如,UDP 就是这样)。 There is no 1-to-1 relationship between sends and reads.发送和读取之间没有一对一的关系。 Sent data can be joined and fragmented in whatever packets the network deems necessary for efficient transmission.发送的数据可以在网络认为有效传输所需的任何数据包中加入和分段。 The only guarantees that TCP provides you are: TCP 为您提供的唯一保证是:

  • data will be delivery (unless the connection is closed or lost)数据将被传递(除非连接关闭或丢失)
  • data will be received in the same order it was sent数据将按照发送的顺序接收

So, to do what you are asking for, you have to explicitly mark where one data ends and the next begins.因此,要执行您的要求,您必须明确标记一个数据的结束位置和下一个数据的开始位置。 For example, by sending the data's length before the actual data, eg:例如,通过在实际数据之前发送数据的长度,例如:

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

This way, the receiver can first read an integer to know how many strings are being sent, then run a loop, where each iteration reads an integer for the string length then reads the bytes for that string, eg:这样,接收者可以首先读取一个整数以了解正在发送多少个字符串,然后运行一个循环,其中每次迭代读取字符串长度的整数,然后读取该字符串的字节,例如:

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