Getting byte arrays using TCP connections

13,155

Solution 1

The answer has 2 parts. Dealing with 2 separate problems your questions is related to.

1. Network facts

TCP is inherently stream based. i.e. Sending byte[1000] first and then byte[1200], is indistinguishable from sending byte[2200] once. What is actually send over the network can very likely be 2 packets, first being a packet with 1400 bytes and the second being 800, or 1401 and 799, and can vary each time. The receiver has no way to know the sender actually sent 1000 bytes first, and then sent 1200 bytes. This is by design in network. Java has nothing to do with this fact. And you can do nothing with it.

2. Java implementation

On the sender side. First, you need OutputStream os = tcpsocket.getOutputStream();. And then, each time, you need os.write(byteArray). On The receiver side, you need InputStream is = tcpsocket.getInputStream();. And then, each time, you need is.read(byteArray). Note that on the receiver side, how much of the byteArray is actually filled will be returned. It may be any number between 1 and the capacity of the byteArray, and is irrelevant to how the sender actually sent it.

To ease the task, you may use DataInputStream is = new DataInputStream(tcpsocket.getInputStream()); at the beginning, and use is.readFully(byteArray) each time you need to read something. This way, it can be guaranteed that byteArray will always be filled.

But you can never know how many bytes you should receive if the actual length is variable unless you add some extra information. For example, send the length first, using 4 bytes. How you will actually do this is usually closely related to your actual use case. And it's up to you

Solution 2

in order to implement a message based protocol over a socket (stream), you basically want to come up with some message format, then read/write that on either end of the connection. a very simple format is to write the length of the message as a 4 byte int, then send the message bytes (then flush the stream). on the receiving end, read a 4 byte int, then read exactly that many following bytes (be careful that you limit your read method call or you may accidentally read part of the next message).

public void writeMessage(DataOutputStream dout, byte[] msg, int msgLen) {
  dout.writeInt(msgLen);
  dout.write(msg, 0, msgLen);
  dout.flush();
}

public byte[] readMessage(DataInputStream din) {
  int msgLen = din.readInt();
  byte[] msg = new byte[msgLen];
  din.readFully(msg);
  return msg;
}
Share:
13,155
Dao Lam
Author by

Dao Lam

I'm just a normal college kid majoring in Computer Science. I got my CS degree! I'm young kind of young and definitely still have A LOT to learn. To those of you who answered my questions, thank you very much. People like you give me the courage to continue pursuing my passion. I really really appreciate it! :) Feel free to visit my website here for more information about me/my projects.

Updated on June 04, 2022

Comments

  • Dao Lam
    Dao Lam almost 2 years

    I was using UDP to send/receive data but I now want to switch to TCP to avoid packet loss.

    I've read several tutorials on TCP and noticed that instead of using DatagramPacket like UDP, TCP uses InputStream/OutputStream.

    How do we get the byte[] from DataInputStream, something that's similar to this:

    byte[] receiveData = new byte[64000];
    DatagramPacket receivePacket = new DatagramPacket(receiveData,receiveData.length); 
    receiveData=receivePacket.getData();
    
  • Dao Lam
    Dao Lam almost 12 years
    Thank you for your thorough answer. I really appreciate it! :)
  • Haozhun
    Haozhun almost 12 years
    @DaoLam I feel glad you like it.
  • Dao Lam
    Dao Lam almost 12 years
    How do you initialize your byte array since you don't know the size of it yet? I initialized its size as 64000 but that's causing me an arrayindexoutofbounds problem somewhere else in my code.
  • Haozhun
    Haozhun almost 12 years
    @DaoLam This is true. That's why I wrote the last paragraph. If you can elaborate on what you need to do, I can probably give you a suggestion on how you can make it work.
  • Dao Lam
    Dao Lam over 11 years
    Should the number of bytes received ALWAYS be less than or equal to the actual length being sent? I tried doing the following to get the size of the received array: int x = is.read(byteArray); System.out.println(x); but x is actually larger than the size of the byteArray that was sent. Should this be happening or am I doing something wrong?
  • Haozhun
    Haozhun over 11 years
    @DaoLam I'm sorry for the late reply. x will not be larger than the actual length of the byte array sent however long the byteArray on the receiver side is. Can you post some code to give us a more complete view of your problem? Maybe posting a new question for your current problem is a faster way to solve your problem. You can add a link to the new question here if you wish.
  • Dao Lam
    Dao Lam over 11 years
    Thank you! I actually solved the problem using ObjectOutputStream.