This will hopefully be the first post of several on different network connections. User Datagram Protocol (UDP) is defined by a Request for Comments (RFC) RFC 768. The purpose of this protocol is sending data across a network. Sending data across a network is like sending a letter in the mail. It requires an address and requires both the sender and receiver to have access to the delivery network.
Computers don’t have a physical address. They have a set of numbers called an IP Address as well as a Port. The IP Address tells the network which computer will receive a particular message. There are many applications that run on a computer as well, and more than one program can be networked. To be able to determine which application to send a message to the computer also has a Port number. Different applications bind to different port numbers so they can receive messages from the network.
User Datagram Protocol (UDP) is built on the idea that a network in potentially unreliable. Much like a message in the postal mail being lost, particular packets can be lost which is why we consider the networks unreliable. Transmission Control Protocol (TCP) is a reliable method of communication but this protocol has a performance penalty and can slow things down in real time systems. Developers can create reliable protocols on top of UDP as well.
In computing we think of servers as computers or applications that will receive messages, process messages, and send us a response. Client generally means any application that connects to the server and sends a message, but generally doesn’t process other users requests. So while this is not always the case, generally speaking there is a many to one relation between clients and servers.
Server
Generally we need a server first. Someone listening to the request. Then we can create a client to send requests to the server. In computers there are many names for a process that stays active – process, background task, service, daemon process, thread etc. For creating a server we need a process that will stay in an active state of listening for messages. Much like someone watching a horizon for a smoke signal, once the server receives the message it will be able to process that message and possibly send a response to the return IP address of the client.
Below is an example of creating a UDP server in Java. The code launches a UDP Server thread that will listen on Port 7777. The method uses a threadpool to launch the server. Other UDP server threads with different ports could be launched on the same threadpool. The IP Address 127.0.0.1 is usually associated with localhost. Both of these example applications are on the same computer for testing. In a network scenario these IP addresses would need to be replaced with the IP addresses or the hostname would need to be resolved into an IP address so we could send the message to that computer.
Standard Disclaimer: The below code is licensed under the MIT license, so do with it as you wish and please understand this was provided as an example so there are no guarantees it is tested properly or will work 100% of the time.
Main method:
private static Logger logger = Logger.getLogger(UpdServerContainer.class.toString());
private static UdpServer server = new UdpServer(7777);
private static BlockingQueue workQueue = new ArrayBlockingQueue(10);
public static void main(String args[]) {
logger.setLevel(Level.INFO);
logger.info("System is running...");
byte[] receiveData = new byte[16384];
ThreadPoolExecutor executor = new ThreadPoolExecutor(4,4,10000,TimeUnit.MILLISECONDS,workQueue);
executor.execute(server);
}
Below creates a UDP server in Java configured to non-blocking input output (NIO). Non blocking input allows us to not leave the current thread or process idling while waiting to receive messages. Blocking threads can add value in situations where lots of data does not need to be processed quickly, and other ports or input can be processed as well within the same thread.
An article that discusses the difference between IO and NIO: http://tutorials.jenkov.com/java-nio/nio-vs-io.html
UpdServer class:
public class UdpServer implements Runnable {
private static Logger logger = Logger.getLogger(UdpServer.class.toString());
private static int BUFFER_SIZE = 16384;
private int port;
private DatagramChannel channel;
private DatagramSocket outgoingSocket;
private ArrayBlockingQueue receivedMessageQueue = new ArrayBlockingQueue(10000);
private ArrayBlockingQueue sendMessageQueue = new ArrayBlockingQueue(10000);
public UdpServer(int port) {
this.port = port;
}
private void createUdpServer() throws SocketException {
try {
channel = DatagramChannel.open();
channel.configureBlocking(false);
} catch (IOException e) {
e.printStackTrace();
}
outgoingSocket = new DatagramSocket();
channel.socket().bind(new InetSocketAddress(port));
logger.info("UDP Server created and bound to port "+port);
}
@Override
public void run() {
byte[] receiveData = new byte[BUFFER_SIZE];
ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
try {
createUdpServer();
while (true) {
buffer.clear();
channel.receive(buffer);
buffer.flip();
if (buffer.hasRemaining()) {
String receivedMessage = new String(buffer.array());
receivedMessage = receivedMessage.substring(0,receivedMessage.indexOf("\n"));
logger.info("Message received: "+receivedMessage);
receivedMessageQueue.put(receivedMessage);
}
if (!sendMessageQueue.isEmpty()) {
DatagramPacket sendPacket = sendMessageQueue.poll();
outgoingSocket.send(sendPacket);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public ArrayBlockingQueue getReceivedMessageQueue() {
return receivedMessageQueue;
}
public void setReceivedMessageQueue(ArrayBlockingQueue receivedMessageQueue) {
this.receivedMessageQueue = receivedMessageQueue;
}
public ArrayBlockingQueue getSendMessageQueue() {
return sendMessageQueue;
}
public void setSendMessageQueue(ArrayBlockingQueue sendMessageQueue) {
this.sendMessageQueue = sendMessageQueue;
}
public void sendMessage(DatagramPacket packet) throws InterruptedException {
this.sendMessageQueue.put(packet);
}
public boolean hasMessagesReady() {
return !this.receivedMessageQueue.isEmpty();
}
}
Example client:
Below is an example client application that sends to the UDP Server above. We create a DatagramPacket with data and an IP address. Then we send it over a datagram socket to port 7777.
public class UdpClient {
public static void main(String[] args) {
System.out.println("Client is running...");
byte[] sendData = new byte[16384];
try {
InetSocketAddress IPAddress = new InetSocketAddress("127.0.0.1", 7777);
DatagramSocket socket = new DatagramSocket();
String testData = "Test 123";
sendData = testData.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData,sendData.length,IPAddress);
socket.send(sendPacket);
System.out.println("Data sent: "+testData);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Server output:
INFO: System is running…
INFO: UDP Server created and bound to port 7777
INFO: Message received: Test 123
Client output:
Client is running…
Data sent: Test 123
I hope this gives people a working starting example for UDP servers.
Best Regards