Are datagrams always received completely? - java

Most datagram receiving functions such as c's recv or read, javas DatagramPacket class or pythons SocketServer, include the possibility to find out the amount of received data.
c:
int amount = recv(sock, buf, n, MSG_WAITALL);
java:
int amount = datagramSocket.getLength();
python:
class MyUDPHandler(socketserver.BaseRequestHandler):
def handle(self):
amount = len (self.request[0])
Are these reliable? Or is it possible that only parts of the message are received, due to for example packet fragmentation or network delay?
In other words: When I send a variable length chunk of data via udp and receive it at the other end, are these amount values exactly equal to the size of the original chunk?
Edit:
ninjalj made a good point and I want to include it here. What happens when the receiving function is interrupted, for instance by a signal? What happens when two threads simultaneously try to receive from the same socket?

UDP datagrams cannot be partially delivered¹; they are delivered as-is or not at all. So yes, you can be sure that the received datagram was sent exactly as you see it on the receiver's end.
Edit to incorporate Will's comment which is the best kind of correct (i.e., technically):
¹They can be fragmented at the IP level, but the network stack on the receiver side will either fully reassemble a datagram and pass it to the listening process as sent, or will not acknowledge that any data at all has been received.

Partial datagrams are only permissible with UDP Lite.

Related

Need to reassemble tcp packets with netty

currently I am working with an inhouse protocol where I send a request to our hardware and receive the answer with netty. In the message which I receive are several bytes which tell me how many bytes the answer will contain.
In my channelRead method I wait until the readable bytes of the recieved message are equal or greater than the expected bytes to make sure I get all data.
if (((ByteBuf) msg).readableBytes() >= dataSize) {
//do something with the bytes
ctx.close();
((ByteBuf) msg).release();
}
This works fine if I receive exactly one tcp package from the hardware. Sometimes the hardware splits the TCP frame into several packages and my channelRead waits for ever.
Is there a simple way in netty to reassemble these packets in the channelRead method?
Just extend ByteToMessageDecoder. This will handle all the buffering for you. Check the javadocs for more details and an example.

Datagramsocket: how receive(...) handles fragmentation of a packet

I came to know from my Professor that, a datagram packet sent using UDP socket gets fragmented in the lower layers and may arrive as multiple packets at the receiver end. For e.g, if I send a 1000 bytes data in a datagram packet, at the receiving end it might arrive as, say 2 bytes, 500 bytes, 12 bytes, and so on. Therefore, he suggested to do multiple receive(...) to receive the entire 1000 byte packet sent by the sender.
Later when I went through the Java documentation for datagram socket receive(...) and there is a line that reads as follows: "This method blocks until a datagram is received. ..." Does it mean that entire datagram packet is received and don't need to do multiple receive (even though it's the case in theory) when we use Java?
Pls. clarify. If multiple receive(...) for each packet is the only option to get around this problem, pls. give suggestions on how to do this.
Any call to receive() will give you an entire packet - the fragment handling happens in two layers below the socket. The fragmentation and defragmentation happens in the Network/Internet layer (IP), so the socket will never see the fragments but only receive entire and full UDP/TCP packets (only full packets gets sent to the listening port).
So, no, you do not need multiple receive() to get a single packet, but you should be aware that UDP is not reliable so if one fragment gets lost in the Network layer (and in some cases if it arrives out of order), you won't be able to get the packet.
You might also want to check the methods getReceiveBufferSize() and setReceiveBufferSize() if you're having trouble receiving packets - if the buffer size is smaller than the packet size, it's not guaranteed that you can receive the packet.

Java Socket issue, buffer receives two packets at same time.

I am using Java Socket API for communication. But sometime I am getting, packet attached in single packet. How can I avoid the same. Is there any method to resolve same in Java NIO or java NIO 2. I am sure that packets are coming separately. But both stored in single buffer.
Please note that here Packet is nothing but logical separation of data. The data is send by third party system. They send one by one. But I am receiving two packet at same time.
This is the way it's supposed to work. TCP uses packets to transfer data, but it's not visible from the high-level socket API : you open a output stream and send as much data as you want. This data is split into packets by the TCP/IP protocol stack. And at the receiving side, you open an input stream and receive the data, without knowing it has been split into packets.
If you want two application-level packets, then design a transfer protocol using separators between your packets, or fixed-size chunks of data, or anything else allwoing to distinguish what is part of a logical packet and what is part of the next one.

How to detect retransmited packets to discard them in TCP Sockets in java

I sometimes receive already received packets (I used sniffer and system ACKs them). Now I read all data (until socket timeout) and then send new request, but this is ugly. I was thinking about using sequence numbers but i didn't find it in Socket interface. Any clues?
No you don't. If the receiving TCP stack misses a packet, it will re-request it, but it can't have delivered the original one to you, because it missed it. And if it gets a packet it has already received, it will drop it.
TCP will deliver all the bytes that are sent, in the order they are sent. Nothing else (well, except some edge cases around disconnects).
Something else is going on.
EDIT:
To be clear, I'm talking about the bytes that are delivered to your application through the socket's InputStream. What happens on the wire is largely irrelevant unless you have some horrific network retransmission problem that you're trying to investigate. And if the receiving stack does get a duplicate packet, it will ACK it, because if it didn't then the sender would re-send it... again.
It sounds like you're trying to account for things that TCP already takes care of. It has sequence numbers built in and will take care of any lost data for you, and from the receiving point you should be waiting until you receive all your expected data, rather than reissuing a request. If you don't want to wait for a response to complete before issuing a new request, consider pipe-lining requests with multiple connections.

"Lost" UDP packets (JBoss + DatagramSocket)

I develop part of some JBoss+EJB based enterprise application. My module needs to process huge amount of incoming UDP packets. I've done some load testing and it looks that in case of sending packets with 11ms interval everything is fine, but in case of 10ms interval some packets are lost. It's rather strange in my opinion, but I done 10/11ms interval load tests comparison several times and it is always the same result (10 ms - some "lost" packets, 11ms - everything's fine).
If it was something wrong with synchronization, I'd expect that it will also be visible in case of 11ms tests (at least one packet lost, or at least one wrong counter value).
So if it is not because of synchronization, then maybe DatagramSocket through which I receive packets doesn't work as expected.
I found that receive buffer size (SO_RCVBUF) has default 57344 value (probably it's underlying IO network buffers dependent). I suspect, that maybe when this buffer goes full, then new incoming UDP datagrams are rejected. I tried set this value to some higher, but I noticed that if I exaggerate, buffer returns to its default size. If it's underlying layer dependent how can I find out maximum buffer size for certain OS/network card from JBoss level?
Is it possible that it is caused by receive buffer size, or maybe 57344 value is big enough to handle most cases? Do you have any experience with such issues?
There is no timeout set on my DatagramSocket. My UDP datagrams contains about 70 bytes of data (value without datagram header included).
[Edited]
I have to use UDP because I receive Cisco Netflow data - it is protocol used by network devices to send some traffic statistics. Also, I have no influence on sent bytes format (e.g. I cannot add counters for packets and so on). It is not expected that all packets will be processed (some datagrams may be lost), but I'd expect that I will process most of packets. During 10ms interval tests, about 30% of packets were lost.
It is not very possible that slow processing causes this issue. Currently singleton component holds reference to DatagramSocket calling receive method in a loop. When packet is received, it is passed to the queue, and processed by picked from pool stateless component. "Facade" Singleton is only responsible for receiving packets and passing it on to the processing (it does not wait for processing complete event).
Thanks in advance,
Piotr
UDP does not guarantee delivery, so you can tweak parameters, but you can't guarantee that the message will get delivered, especially in the case of very large data transfers.
If you need to guarantee delivery, you should use TCP instead.
If you need (or want) to use UDP, you can encode each packet with a number, and also send the number of packets expected. For example, if you sent 10 large packets, you could include the information: packet 1/10, packet 2/10, etc. This way you can at least tell if you have not received all of the packets. If you have not received them, you could send a request to resend those missing packets.
UDP is inherently unreliable.
Datagrams can be thrown away at any point between sender and receiver, even within the receiver at a level below your code. Setting the recv buffer to a larger size is likely to help the networking code within your machine buffer more datagrams but you should expect that some datagrams will be lost anyway.
If your recv logic takes too long (i.e. longer than it takes for a new datagram to arrive) then you'll always be behind and you'll always miss datagrams eventually. All you can do is make sure that your recv code runs as fast as possible, perhaps move the inbound datagram to a queue and process it 'later' or on another thread but then that will just move your problem to being one where you have a queue that keeps growing.
[Re your edit...] And what's processing your queue and how does the locking work between the producer and the consumers? Change your code so that the recv logic simply increments a count and discards the data and loops back around and see if you're losing fewer datagrams; either way, UDP is unreliable, you WILL have datagrams that are discarded and you should just expect that and deal with it. Worrying about it means you're focusing on the wrong problem; make use of the data you DO get and assume that you wont get much of it and then your program will work even if the network gets congested and MOST of your datagrams get discarded.
In summary, that's just how is it with UDP.
It appears in your tests that only up to two packets can be in the buffer so if each packet is less than 28KB this should be fine.
As you know UDP is lossy, but you should be able to send more than one packet per 10 ms. I suggest you write a simple receiver which just listens to packets just to determine if its your application or something at the network/OS level. (I suspect the later)
I don't know Java but ... does the API allow you to invoke an asynch listen/receive for a datagram:
Use O/S API to do a receive (passing your application-level buffer as a paremeter)
(Wait while there's nothing to receive...)
(O/S receives something from the network...)
O/S puts the received packet into the buffer and completes/returns your API call
If that's true then I suggest that you do several concurrent instances of the API call, so that there are several concurrent application-level buffers into which multiple packets can be received.

Categories