How does TCP_NODELAY affect consecutive write() calls? - java

TCP_NODELAY is an option to enable quick sending of TCP packets, regardless of their size. This is very useful option when speed matters, however, I'm curious what it will do to this:
Socket socket = [some socket];
socket.setTcpNoDelay(true);
OutputStream out = socket.getOutputStream();
out.write(byteArray1);
out.write(byteArray2);
out.write(byteArray3);
out.flush();
I tried to find what flush actually does on a SocketOutputStream, but as far as I know now, it doesn't do anything. I had hoped it would tell the socket "send all your buffered data NOW", but, unfortunately, no it doesn't.
My question is: are these 3 byte arrays sent in one packet? I know you don't have much control over how TCP constructs a network packet, but is there any way to tell the socket to (at least try to) pack these byte arrays, so network overhead is avoided? Could manually packing the byte arrays and sending them in one call to write help?

My question is: are these 3 byte arrays sent in one packet?
As you have disabled the Nagle algorithm, almost certainly not, but you can't be 100% sure.
I know you don't have much control over how TCP constructs a network packet, but is there any way to tell the socket to (at least try to) pack these byte arrays
Yes. Don't disable the Nagle algorithm.
so network overhead is avoided? Could manually packing the byte arrays and sending them in one call to write help?
Yes, or simpler still just wrap the socket output stream in a BufferedOutputStream and call flush() when you want the data to be sent, as per your present code. You are correct that flush() does nothing on a socket output stream, but it flushes a BufferedOutputStream.

Could manually packing the byte arrays and sending them in one call to write help?
Yes, send them all in a single call to write. This will maximize the chances that your bytes will be sent in a single packet.
Of course, you can never know, since there are too many variables involved - different OSs and lots of different networking gear between you and your peer, but if you give the OS the ability to pack everything together, it will generally try to.
If you disable nagle and make seperate system calls (remember, the OS controls the sockets, not your appliation or java), you're asking the OS to send them individually. The OS has no idea you're about to call write again with some more data.

Related

Java/Android- How to use ObjectOutputStream to write a large size of List object in TCP/IP socket programming

I recently use ObjectOutputStream to write objects in TCP/IP socket programming.
If I want to write a large size of List<Object>/ArrayList<Object> through the socket
(e.g. list.size: 100, the total bytes may larger than the payload size),
should I just call writeObject(List<Object>/ArrayList<Object>)?
Is that OK, or any Exception occurs?
Does ObjectOutputStream automatically split the list to a few segments before sending the packets? Or it doesn't support?
Is there another way to send a large size of an object?
As for ObjectInputStream, can I just call readObject() to receive the large size of List<Object>/ArrayList<Object>?
Thanks in advance.
->
Another questions: Does ObjectInputStream receive anything when the list is not fully sent from the sender?
I want to close the socket but the ObjectOutputStream is still sending the list. Does it shutdown immediately when I close socket, and the list segments are destroyed?
Is that OK, or any Exception occurs?
It's ok.
Does ObjectOutputStream automatically split the list to a few segments
Yes.
before sending the packets? Or it doesn't support?
The underlying socket has no control over how packets are sent. Nor should you need it.
Is there another way to send a large size of an object?
Many but 100 isn't very large. If you had a few million of large objects it might be worth it. If you have a few billion you definitively need to consider alternatives. There is lots of alternatives but I wouldn't bother unless you need it.
As for ObjectInputStream, can I just call readObject() to receive the large size of List/ArrayList?
Yes, that is what it is for.
should I just call writeObject(List<Object>/ArrayList<Object>)?
Yes.
Is that OK, or any Exception occurs?
It is OK, but exceptions can always occur, especially over a network.
Does ObjectOutputStream automatically split the list to a few segments before sending the packets? Or it doesn't support?
Yes, and TCP does as well, and IP.
Is there another way to send a large size of an object?
Why? You have this way. You don't need another way.
As for ObjectInputStream, can I just call readObject() to receive the large size of List<Object>/ArrayList<Object>?
Yes.

Sockets (in Java). Splitting byte chunks

Lets say you have a continious binary stream of data. And each of data's pieces should be somehow split. What is the best way to do it?
Socket.read(byte[] arr) doesnt guarantee that you will recieve exactly the same ammount of bytes as you sent using Socket.write(byte[] arr) arr may be split (out of 10 bytes you first read 8 and then 2) or spliced.
One of the ways of solving this is specifying incoming byte array's size first. Read exactly 4 bytes, convert them into an Integer x, then read x bytes. But this only works in TCP and may completely mess everything up if just one time you will send wrong byte array size
Another one I can think of is prefixing chunks of data with a pseudo random byte sequences. Initialize Random on client and server with the seed and use its random.nextBytes(byte[] arr) for prefixes. The downside of it is that in order to make sure that there is a very little possibility of having a random sequence in an actual data chunk you have to make it pretty long. That will add up a lot of useless traffic. And again it is not a way out in UDP sockets.
So what are other good ways of doing this and are there any simple libraries which would allow me to simply do conn.sendDataChunk(byte[] arr) ?
One of the ways of solving this is specifying incoming byte array's size first. Read exactly 4 bytes, convert them into an Integer x, then read x bytes.
Yep, that's exactly what you should do. In other words, you're adding a message header before each message. This is a practical necessity when you want to layer a message-based network protocol atop of a stream-based one that has no concept of message boundaries. (TCP purposefully obscures the IP packet boundaries.)
You could also use this as an opportunity to add other fields to the message header, such as a message ID number to help you distinguish between different message types.
But this only works in TCP and may completely mess everything up if just one time you will send wrong byte array size.
This is true. So don't send a malformed header!
In all seriousness, a header with a length field is standard practice. It's a good idea to add sanity checks on the length: make sure it's not too large (or negative) so you don't end up allocating 2GB of memory to read the next message.
Also, don't assume you can read the whole header in with a single read() either. It may take multiple reads to get the whole header.
Regarding UDP sockets: reading a UDP socket is not the same as reading a TCP socket. You either get the UDP packet or you do not. From UDP:
Datagrams – Packets are sent individually and are checked for integrity only if they arrive. Packets have definite boundaries which are honored upon receipt, meaning a read operation at the receiver socket will yield an entire message as it was originally sent.
So for UDP, you do not need to worry about reading an incorrect number of bytes. But you do have to worry about what happens if some data does not arrive, or if it arrives in a different order than it was sent.

High Speed file transmission through WIFI

everyone. I am a beginner in network programming. Currently, I want to do an experiment which sends a file(~2M bytes) from Android phone to Ubuntu server. How can I send it at the highest speed? I have tried something like using Bufferedreader in Java, reading each byte out of the file and sending that single byte to server through socket "outputstream write" function. This way seems to cost too much time. I notice that if in the same network condition, I send same file using some Immediate Messenger tools,like Skype;it is much quicker than I did. Does anybody know the API or implementation protocol beneath those Immediate Messenger software?
I probably need to call other efficient APIs other than socket? I am also trying to read the whole file into a byte array and then call "socket write" function to send the huge byte array to server for a just single time.Although when I receive it at server side to found that there are a lot of "padding zeros" distributed in my original data, the whole transfer seems to cost less time than the "single byte transfer" method. Anybody has any advice on this?Thanks a lot!
Thanks for everybody's answer. I think I just made a silly mistake. The real reason for my slow transmission using TCP socket is that every time I just read a single byte out of the file and call "void write(int b)" to send this single byte to server.This method is very time consuming. Now every time I try to read 256 bytes out of file and send these 256 bytes through "void write(byte[] b,int off,int len)";in this way, the transmission is pretty fast.Therefore, it is not the problem of TCP itself. It is my mistake of calling the wrong API. I have not tried UDP yet. But I think it is also a good choice.Thanks again,everybody.
Short of reinventing TCP/IP the fastest way to send will be via UDP, if your connection is good enough (few losses) than you on;y need to implement packet sequence so the sender prepends sequence number to the data packets, the receiver keeps track of missed packets and requests them again after all data is sent. After all data is received the receiver can reassemble the complete file.
This is simplistic implementation of TCP over UDP.

Side effects of flush() OutputStreamWriter to Network

What are the side effects of flushing a OutputStreamWriter which is going to a network socket.
I have a program which calls out.flush() after every few bytes. Is there any reason why I should wait until all bytes I need are in the buffer?
Will I get lower transfer rate if I flush too much (more overhead)?
Will this slow down execution of my program (blocking)?
Each time you write to a socket, you add between 5 and 15 micro-seconds. For buffered output, this occurs when you flush() the data. Note: if you don't have a buffered output, it will be performed on every write() and the flush() won't do anything.
Fortunately the OS expects applications to make more calls than is optimal so the it uses Nagle's algorithm by default to groups portions of the data writing into a larger packets. Note: not only does the OS do this but some network adapter do this by default too.
In short, don't flush() too often but unless tens of micros-seconds add up to something which matters to you, you might not notice the difference. e.g. if you do 100 flushes you might add a milli-second.
There is no reason to flush unless:
you want the peer to receive the data as soon as possible
you've sent a buffered request and you're now going to read the response.
In other cases it is better to allow the buffer, the Nagle algorithm, and the TCP receive window work their magic.
In case of data transfer on network, batching of outputStreamWriter's flush does improve performance.
I observed that single flush of data packet of about 520 bytes was taking around 3 milliseconds.

why does this Java programme cause UDP packet loss?

I'm running experiments on my machine A and B, both with Ubuntu Server 11.04 installed. A and B are connected to the same 1000M/bps switch.
A is the sender:
while (total<=10,000)
send_udp_datagramPacket(new byte[100]) to B
B is the receiver:
while(true)
receive()
But finally I got less than 10,000 (about 9960) at B. Why is this happening?
Where did the lost packets go? Were they not actually sent to the wire to the switch? Or the switch lost them? Or they indeed got to B, but B's OS discarded them? Or they reached to Java, but Java threw them away because of a full buffer?
Any reply would be appreciated.
Remember, UDP does not provide reliable communication, it is intended for situations in which data loss is acceptable (streaming media for instance). Chances are good that this is a buffer overflow (my guess, don't rely on it) but the point is that if this data loss is not acceptable, use TCP instead.
If this is just for the sake of experimentation, try adding a delay (Thread.sleep()) in the loop and increase it until you get the maximum received packets.
EDIT:
As mentioned in a comment, the sleep() is NOT a fix and WILL eventually loose packets...that's just UDP.
But finally I got less than 10,000 (about 9960) at B. Why is this happening?
UDP is a lossy protocol. Even if you got 10,000 in this test you would still have to code for the possibility that some packets will be lost. They can also be fragmented (if larger than 532 bytes) and/or arrive out of order.
Where did the lost package go?
They were dropped.
Were they not actually sent to the wire to the switch?
They can be dropped just about anywhere. I don't believe Java has any logic for dropping packets (but this to is not guaranteed in all implementations) It could be dropped by the OS, the network adapter, corrupted on the wire, dropped by the switch.
Or the switch lost them?
It will do this if the packet arrived corrupt in some way or a buffer filled.
Or they indeed got to B, but B's OS discarded them?
Yes, or A's OS could have discarded them.
Or they reached to Java, but Java threw them away because of a full buffer?
Java doesn't have its own buffers. It uses the underlying buffers from the OS. But the packets could be lost at this stage.
Note: No matter how much you decrease the packet loss, you must always allow for some loss.
Why does this Java programme cause UDP packet loss?
The question is ill-formed. Neither Java nor your program causes UDP packet loss. UDP causes UDP packet loss. There is no guarantee that any UDP packet will ever arrive. See RFC 768.

Categories

Resources