简体   繁体   中英

Java send data over TCP Socket seperately

I want to send multiple packets separately with using tcp socket in Java. 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?

Why do i want this ? Because in my client there's an event that listens the coming tcp packages. This event must be triggered for each elements of array separately.

TCP logically represents a continuous stream, similar to a file. 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.

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).

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.

TCP is a stream of bytes, it has no concept of message boundaries (like UDP does, for instance). 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:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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