In java NIO, does Selector.select() guarantee that at least one entire UDP datagram content is available at the Socket Channel, or in theory Selector could wake when there is less then a datagram, say couple of bytes ?
What happens if transport protocol is TCP, with regards to Selector.select(), is there difference to UDP ?
From the API:
Selects a set of keys whose corresponding channels are ready for I/O operations.
It doesn't however specify what ready means.
So my questions:
how incoming datagrams/streams go from hardware to Java application Socket (Channels).
when using UDP or TCP client, should one assume that at least one datagram is received or Selector could wake when there is only a part of datagram available ?
It doesn't however specify what ready means.
So my questions:
how incoming packages/streams go from hardware to Java application Socket (Channels).
They arrive at the NIC where they are buffered and then passed to the network protocol stack and from there to the socket receive buffer. From there they are retrieved when you call read().
when using UDP or TCP client, should one assume that at least one package is received
You mean packet. Actually in the case of UDP you mean datagram. You can assume that an entire datagram has been received in the case of UDP.
or Selector could wake when there is only a part of [packet] available?
In the case of TCP you can assume that either at least one byte or end of stream is available. There is no such thing as a 'package' or 'packet' or 'message' at the TCP level.
Related
I'm using DatagramPacket and DatagramSocket classes in Java to send messages with UDP. I have incomplete knowledge about networking. I know that:
when a datagram is sent, it may in fact be split into multiple pieces of data travelling independently on the network (for example, if my datagram length is greater than MTU).
UDP does not guarantee the order of messages at receiving (and does not guarantee the receiving of messages at all).
Putting this information together, I "understand" that if I send one (large) DatagramPacket, I may receive the bytes of my datagram in any order (and some parts may even be missing)! But I think I misunderstood something because if it was the case, nobody would use such a protocol.
How can I ensure that the datagram I receive (if I receive it) is equal to the datagram I have sent?
Your understanding is incorrect. If your datagram is broken into fragments by IP (below the UDP layer) at the sending side, then IP at the receiver will reassemble those fragments in the correct order before passing the entire reassembled datagram up to the receiver's UDP layer. If any fragments of the datagram are lost then the reassembly will fail, the partially-reconstructed datagram will be discarded, and nothing will be passed up to the receiver's UDP layer. So the receiving UDP -- and therefore the receiving application -- gets either a complete datagram or nothing. It will never get a partial datagram, and it will never get a datagram whose content has been scrambled because of fragmentation.
The receiving application can be given a partial (truncated) datagram if the incoming datagram is larger than the application's receive buffer, but that has nothing to do with fragmentation.
Putting this information together, I "understand" that if I send one (large) DatagramPacket, I may receive the bytes of my datagram in any order
No.
(and some parts may even be missing)!
No.
You will receive a UDP datagram intact and entire or not at all.
But I think I misunderstood something because if it was the case, nobody would use such a protocol.
Correct. It isn't the case.
How can I ensure that the datagram I receive (if I receive it) is equal to the datagram I have sent?
It always is. If it arrives. However it may arrive zero, one, or more times, and it may arrive out of order.
The generally accepted maximum practical UDP datagram size is 534 bytes of payload. You are guaranteed that IP will not fragment that, either at the sender or at any intermediate host, and non-fragmentation decreases your chance of packet loss. (If any fragment is lost the datagram is lost, as stated by #ottomeister.)
If sequence is important to you, you need sequence numbers in your datagrams. This can also help to protect you against duplicates, as you know what sequence number you're up to so you can spot a duplicate.
If arrival is important to you, you need an ACK- or NACK-based application protocol.
I understand that Server socket channel is registered to listen for accept, when accepted a channel is registered for read and once read it is registered for write and this is done by adding the relevant keys to the SelectionKey's interest set using the interestOps method.
However, when we remove some interestOps from a key for e.g key.interestOps(key.interestOps() & ~SelectionKey.OP_READ);
What actually happens here? Does this mean that the server will just not listen for any incoming requests to channel belonging to this socket, and the source channel will be oblivious of this decision by the server and might keep on sending data to the server? Or will it somehow inform the channel source of this decision.
In packet switching parlance, is the above operation effectively the same as server receiving packets and just dropping the packet if the interestKeys for the channel this packet belong to have been "unset"
However, when we remove some interestOps from a key for e.g key.interestOps(key.interestOps() & ~SelectionKey.OP_READ);
What actually happens here?
What literally happens is something like:
public void interestOps(int interestOps)
{
this.interestOps = interestOps;
}
Does this mean that the server will just not listen for any incoming requests to channel belonging to this socket
It means that the Selector won't trigger any OP_READ events if data arrives via the socket. It doesn't mean that data won't be received.
and the source channel will be oblivious of this decision by the server and might keep on sending data to the server?
If by 'source channel' you mean the peer, it is not advised in anyway, unless the receive buffer fills up at the receiver.
Or will it somehow inform the channel source of this decision.
No.
In packet switching parlance, is the above operation effectively the same as server receiving packets and just dropping the packet if the interestKeys for the channel this packet belong to have been "unset".
No.
I have tcp communication via socket code like :
public void openConnection() throws Exception
{
socket = new Socket();
InetAddress iNet = InetAddress.getByName("server");
InetSocketAddress sock = new InetSocketAddress(iNet, Integer.parseInt(port));
socket.connect(sock, 0);
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
and send method as :
synchronized void send(String message)
{
try
{
out.println(message);
}
catch (Exception e)
{
throw new RuntimeException(this.getClass() + ": Error Sending Message: "
+ message, e);
}
}
And I read from webpages that, TCP/IP does not guarantee delivery of packet, it retries but if network is too busy, packet may be dropped([link]).1
Packets can be dropped when transferring data between systems for two key reasons:
Heavy network utilization and resulting congestion
Faulty network hardware or connectors
TCP is designed to be able to react when packets are dropped on a network. When a packet is successfully delivered to its destination, the destination system sends an acknowledgement message back to the source system. If this acknowledgement is not received within a certain interval, that may be either because the destination system never received the packet or because the packet containing the acknowledgement was itself lost. In either case, if the acknowledgement is not received by the source system in the given time, the source system assumes that the destination system never received the message and retransmits it. It is easy to see that if the performance of the network is poor, packets are lost in the first place, and the increased load from these retransmit messages is only increasing the load on the network further, meaning that more packets will be lost. This behaviour can result in very quickly creating a critical situation on the network.
Is there any way, that I can detect if packet was received successfully by destination or not, I am not sure that out.println(message); will throw any exception, as this is non blocking call. It will put message in buffer and return to let TCP/IP do its work.
Any help?
TCP is designed to be able to react when packets are dropped on a network.
As your quote says, TCP is design to react automatically to the events you mention in this text. As such, you don't have anything to do at this level, since this will be handled by the TCP implementation you're using (e.g. in the OS).
TCP has some features that will do some of the work for you, but you are right to wonder about their limitations (many people think of TCP as a guaranteed delivery protocol, without context).
There is an interesting discussion on the Linux Kernel Mailing List ("Re: Client receives TCP packets but does not ACK") about this.
In your use case, practically, this means that you should treat your TCP connection as a stream of data, in each direction (the classic mistake is to assume that if you send n bytes from on end, you'll read n bytes in a single buffer read on the other end), and handle possible exceptions.
Handling java.io.IOExceptions properly (in particular subclasses in java.net) will cover error cases at the level you describe: if you get one, have a retry strategy (depending on what the application and its user is meant to do). Rely on timeouts too (don't set a socket as blocking forever).
Application protocols may also be designed to send their own acknowledgement when receiving commands or requests.
This is a matter of assigning responsibilities to different layers. The TCP stack implementation will handle the packet loss problems you mention, and throw an error/exception if it can't fix it by itself. Its responsibility is the communication with the remote TCP stack. Since in most cases you want your application to talk to a remote application, there needs to be an extra acknowledgement on top of that. In general, the application protocol needs to be designed to handle these cases. (You can go a number of layers up in some cases, depending on which entity is meant to take responsibility to handle the requests/commands.)
TCP/IP does not drop the packet. The congestion control algorithms inside the TCP implementation take care of retransmission. Assuming that there is a steady stream of data being sent, the receiver will acknowledge which sequence numbers it received back to the sender. The sender can use the acknowledgements to infer which packets need to be resent. The sender holds packets until they have been acknowledged.
As an application, unless the TCP implementation provides mechanisms to receive notification of congestion, the best it can do is establish a timeout for when the transaction can complete. If the timeout occurs before the transaction completes, the application can declare the network to be too congested for the application to succeed.
Code what you need. If you need acknowledgements, implement them. If you want the sender to know the recipient got the information, then have the recipient send some kind of acknowledgement.
From an application standpoint, TCP provides a bi-directional byte stream. You can communicate whatever information you want over that by simply specifying streams of bytes that convey the information you need to communicate.
Don't try to make TCP do anything else. Don't try to "teach TCP" your protocol.
I create simple diameter client and server (Link to sources). Client must send 10000 ccr messages, but in wireshark i see only ~300 ccr messages will be sended. Other messages raised timeouts on client. I run server and client on different computers with windows 7. I found in JDiameter sources line where jdiameter sended ccr (line 280) and i think in case when sending buffer of socket is full ccr not sended. I add before line 280 this code
while(bytes.hasRemaining())
Client send ~9900 ccr, but very slow.I tested client on other diameter server wroted on c++, client(on jdiameter without my changes) send ~7000 ccr, but this server hosted on debian.
I don't know ways to solve this problem, thanks for any help.
If the sender's send returns zero, it means the sender's socket send buffer is full, which in turn means the receiver's socket receive buffer is full, which in turn means that the receiver is reading slower than the sender is sending.
So speed up the receiver.
NB In non-blocking mode, merely looping around the write() call while it returns zero is not adequate. If write() returns zero you must:
Deregister the channel for OP_READ and register it for OP_WRITE
Return to the select loop.
When OP_WRITE fires, do the write again. This time, if it doesn't return zero, deregister OP_WRITE, and (probably, according to your requirements) register OP_READ.
Note that keeping the channel registered for OP_WRITE all the time isn't correct either. A socket channel is almost always writable, meaning there is almost always space in the socket send buffer. What you're interested in is the transistion between not-writable and writable.
Are those packet simply disappear? or they waits for the destination? Or the packet go back then throws an exception?
And in java, what is the difference between the byte[] buffer with the length, in the DatagramPacket constructor?
DatagramPacket dp = new DatagramPacket(new byte[...], length);
From Wikipedia:
UDP is... Unreliable – When a message
is sent, it cannot be known if it will
reach its destination; it could get
lost along the way. There is no
concept of acknowledgment,
retransmission or timeout.
Even if the destination is online, there is no guarantee, the UDP packet will arrive, arrive in the order sent, or not be fragmented. (I believe packets smaller than 532 bytes will not be fragmented) It is possible to have all three; fragmented, out of order and incomplete for the same packet.
The simplicity and stability of your network will determine how robust UDP packet delivery is, but you have to assume it is unreliable at least some of the time. All you can do is minimise the loss.
It is up to you to decide what to do if a packet is lost and how to detect it.
If you want broadcast, reliable delivery of messages I suggest you look at JMS Topics or Queues, like ActiveMQ.
If using UDP protocol, you can't guarantee that your packet is going to be received.
So the answer is, it will be sent, even if its destination is not online.
TCP protocol, its guaranteed that costumer will receive the packet. Even if he is offline, once he get's online, that packet will be received.
Are those packet simply disappear? or they waits for the destination? Or the packet go back then throws an exception?
What happens depends on the nature of the "offline" status.
If the UDP message reaches the host, but the application is not listening, it will typically be silently discarded. It definitely won't be queued waiting for the application to listen. (That would be pointless, and potentially dangerous.)
If the UDP message cannot get to the host because the host itself is offline, the message will be silently discarded. (If the packets can reach the destination host's local network, then there is nothing apart from the host itself that can tell if the host actually received the packets.)
If the network doesn't know how to route the IP packets to the UDP server (and a few other scenarios), an ICMP "Destination Unreachable" packet may be sent to the sender, and that typically gets reported as a Java exception. However this is not guaranteed. So the possible outcomes are:
the UDP packet is black-holed and the sender gets no indication, or
the UDP packet is black-holed and the sender gets a Java exception.
If the UDP packet is blocked by a firewall, then the behaviour is hard to predict. (Firewalls often "lie" in their responses to unwanted traffic.)
The only situation where you would expect there to be queuing of UDP traffic is when the network is working, the host is working and the application is listening. Limited queuing is then possible if the application is slow in accepting the packets; i.e. it takes too long between successive calls to receive on the datagram socket. But even there, the queueing / buffering is strictly limited, and beyond that the messages will be dropped.