Search code examples
javasocketsnetwork-programmingserversocket

Sending many types at the same time with a socket


I want to send a single stream of data corresponding to a couple of different types (say for simplicity one float and one int) from a Socket to another socket (created from a ServerSocket accept()). However, I am not sure what the best way to achieve this is. If I want to use readInt() or readFloat() it seems that I need to send them separately, and I guess that would not be ideal (but please correct me if I am wrong).

The code would start by doing the following (where say the float will be stored in the first 4 bytes in b, and the int will be stored in the last 4 bytes in b)

ServerSocket socket = new ServerSocket(port);
in=new DataInputStream(socket.accept().getInputStream());

byte[] b = new byte[8];
in.read(b);

So far so good, but I would now like to convert only the first four bytes to a float and the last four bytes to an int. I could do something like

float myFloat = ByteBuffer.wrap(b).getFloat();

to get the float, but how do I get the int? In C++ I would just pass the reference to the fifth element in b, but as I understand it this is not possible in java. Of course I could use some library to create a new array from the last four elements of b, but that seems a bit overkill no? or is that the only way?

Any other suggestions on sending many different types at the same time over a socket are greatly appreciated.


Solution

  • I want to send a single stream of data [...] from a Socket to a ServerSocket

    Sorry to be nitpicky, but you can't do that. A ServerSocket is a mechanism for accepting connection requests and establishing the local end of a socket-based communication channel. That local end, once established, is represented by a Socket, so what you seem to want to do is send data from Socket to Socket.

    But your question seems mainly to be about sending mixed data over the communication channel. In that case, the first question to consider is how the receiver knows what type to attempt to read at any given point. This boils down to having an application-layer communication protocol between the communicating parties. That doesn't have to be formal or grandiose; in your example, there seems to be a shared understanding that the data will be sent as a 32-bit binary float followed by a 32-bit binary int. That's a protocol.

    If I want to use readInt() or readFloat() it seems that I need to send them separately, and I guess that would not be ideal

    I don't see what you mean. Yes, you do need to know which data are ints and which are floats, but that does not distinguish use of DataInputStream.readInt() and DataInputStream.readFloat() from any other mechanism.

    For each datum you transmit, you have two basic alternatives:

    1. count on the receiver to rely on some prior agreement or assumption to determine how to interpret that datum (possibly extending to recognizing the boundaries of its on-the-wire representation), or

    2. along with the datum, transmit metadata that the receiver will use to interpret the datum as intended.

    Of course, (2) can be viewed as a special case of (1).

    If a message will always consist of one float followed by one int, then I don't see anything wrong with the sender using

    myDataOutputStream.writeFloat(f);
    myDataOutputStream.writeInt(i);
    

    and the receiver handling that via

    myDataInputStream.readFloat(f);
    myDataInputStream.readInt(i);
    

    Indeed, for that simple case, I think that's a pretty good choice.

    More generally, however, there are many, many other considerations in choosing or designing a communication protocol. A general discussion of that topic would be far too broad for this venue.