UDP made simple
Abstract: This page describes how to write a simple UDP client/server system in a C/Unix environment. The code is explained step by step.
Motivation: I needed a page like this when working with a small test program for my master’s thesis at Appius / F�lt Communications. It is quite hard to remember all the socket API details off the top of your head, so I wanted a small reference page to get me started quickly without having to wade through tons of man pages. As I did not find a page I liked, I decided to write one. I hope it will be useful for others, too.
Caveats: The code is known to work under recent (fall 1999) versions of Linux. It should work on other Unices too, though some of the header files may be located in other directories on your system.
The server
1 #include 2 #include 3 #include 4 #include 5 #include 6 #include 7 8 #define BUFLEN 512 9 #define NPACK 10 10 #define PORT 9930 11 12 void diep(char *s) 13 < 14 perror(s); 15 exit(1); 16 >17 18 int main(void) 19 < 20 struct sockaddr_in si_me, si_other; 21 int s, i, slen=sizeof(si_other); 22 char buf[BUFLEN]; 23 24 if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1) 25 diep("socket"); 26 27 memset((char *) &si_me, 0, sizeof(si_me)); 28 si_me.sin_family = AF_INET; 29 si_me.sin_port = htons(PORT); 30 si_me.sin_addr.s_addr = htonl(INADDR_ANY); 31 if (bind(s, &si_me, sizeof(si_me))==-1) 32 diep("bind"); 33 34 for (i=0; i40 41 close(s); 42 return 0; 43 >
Comments
- Lines 8-10 define the buffer size (quite arbitrary), the number of packets to receive and the UDP port number to listen at. You could use any port number above 1023, although bind() will fail if someone else is using the same port simultaneously.
- The function diep() is used for error handling.
- 21: Declare receive buffer.
- 22: sockaddr_in is a structure containing an Internet socket address. Basically, it contains:
- an address family (always AF_INET for our purposes)
- a port number
- an IP address
The client
1 #define SRV_IP "999.999.999.999" 2 /* diep(), #includes and #defines like in the server */ 3 4 int main(void) 5 < 6 struct sockaddr_in si_other; 7 int s, i, slen=sizeof(si_other); 8 char buf[BUFLEN]; 9 10 if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1) 11 diep("socket"); 12 13 memset((char *) &si_other, 0, sizeof(si_other)); 14 si_other.sin_family = AF_INET; 15 si_other.sin_port = htons(PORT); 16 if (inet_aton(SRV_IP, &si_other.sin_addr)==0) < 17 fprintf(stderr, "inet_aton() failed\n"); 18 exit(1); 19 >20 21 for (i=0; i 27 28 close(s); 29 return 0; 30 >
- 1: You need to know the IP address of the machine where the server runs. If you run the client and the server on the same machine, try 127.0.0.1. «999.999.999.999» is not a legal IP address; you need to substitute your own server’s address.
- 12: You may call bind() after the call to socket() , if you wish to specify which port and interface that should be used for the client socket. However, this is almost never necessary. The system will decide what port and interface to use.
- 13-19: Here, we set up a sockaddr_in corresponding to the socket address where the server is listening. inet_aton() is used to convert a string in dotted-decimal ASCII notation to a binary address.
- 24: Send BUFLEN bytes from buf to s , with no flags ( 0 ). The receiver is specified in si_other , which contains slen byte.
General tips
- Remember to always check return values from system calls! By doing so, you will save time in the long run, I promise. Many people do not test return values in small quick-and-dirty test programs. However, in such cases it is especially important to check return values, because if you don’t really know what you are doing you are much more likely to make a mistake. The checks help you understand what went wrong and why.
- There is a tool called netcat (the actual command is nc ) which is very useful for testing and debugging socket code. Check the man page if you are curious (of course, it might not be installed on your system).
- If you want to cut and paste the code above, use cut -c9- to get rid of the line numbers. (The exact syntax of cut may be different on your system, and you may have to remove more or less than 9 characters.)
- The command netstat can be useful to check which sockets are active. Try netstat -a .
- For an overview over some of the structures used in socket programming, check out the code examples from lecture 13 on my course in Unix system programming. You will also find some material on TCP programming there. Disregard the initial material on select() and friends. There are some comments in Swedish, but most of the page is written in C.
Programming UDP sockets in C on Linux – Client and Server example
This article describes how to write a simple echo server and client using udp sockets in C on Linux/Unix platform.
UDP sockets or Datagram sockets are different from the TCP sockets in a number of ways.
The most important difference is that UDP sockets are not connection oriented. More technically speaking, a UDP server does not accept connections and a udp client does not connect to server.
The server will bind and then directly receive data and the client shall directly send the data.
Simple UDP Server
So lets first make a very simple ECHO server with UDP socket. The flow of the code would be
socket() -> bind() -> recvfrom() -> sendto()
/* Simple udp server */ #include //printf #include //memset #include //exit(0); #include #include #define BUFLEN 512 //Max length of buffer #define PORT 8888 //The port on which to listen for incoming data void die(char *s) < perror(s); exit(1); >int main(void) < struct sockaddr_in si_me, si_other; int s, i, slen = sizeof(si_other) , recv_len; char buf[BUFLEN]; //create a UDP socket if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) < die("socket"); >// zero out the structure memset((char *) &si_me, 0, sizeof(si_me)); si_me.sin_family = AF_INET; si_me.sin_port = htons(PORT); si_me.sin_addr.s_addr = htonl(INADDR_ANY); //bind socket to port if( bind(s , (struct sockaddr*)&si_me, sizeof(si_me) ) == -1) < die("bind"); >//keep listening for data while(1) < printf("Waiting for data. "); fflush(stdout); //try to receive some data, this is a blocking call if ((recv_len = recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &si_other, &slen)) == -1) < die("recvfrom()"); >//print details of the client/peer and the data received printf("Received packet from %s:%d\n", inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port)); printf("Data: %s\n" , buf); //now reply the client with the same data if (sendto(s, buf, recv_len, 0, (struct sockaddr*) &si_other, slen) == -1) < die("sendto()"); >> close(s); return 0; >
Run the above code by doing a gcc server.c && ./a.out at the terminal. Then it will show waiting for data like this
$ gcc server.c && ./a.out Waiting for data.
Next step would be to connect to this server using a client. We shall be making a client program a little later but first for testing this code we can use netcat.
Test the server with netcat
Open another terminal and connect to this udp server using netcat and then send some data. The same data will be send back by the server. Over here we are using the ncat command from the nmap package.
$ ncat -vv localhost 8888 -u Ncat: Version 5.21 ( http://nmap.org/ncat ) Ncat: Connected to 127.0.0.1:8888. hello hello world world
Note : We had to use netcat because the ordinary telnet command does not support udp protocol. The -u option of netcat specifies udp protocol.
Check open port with netstat
The netstat command can be used to check if the udp port is open or not.
$ netstat -u -a Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State udp 0 0 localhost:11211 *:* udp 0 0 localhost:domain *:* udp 0 0 localhost:45286 localhost:8888 ESTABLISHED udp 0 0 *:33320 *:* udp 0 0 *:ipp *:* udp 0 0 *:8888 *:* udp 0 0 *:17500 *:* udp 0 0 *:mdns *:* udp 0 0 localhost:54747 localhost:54747 ESTABLISHED udp6 0 0 [::]:60439 [::]:* udp6 0 0 [::]:mdns [::]:*
Note the *:8888 entry of output. Thats our server program.
The entry that has localhost:8888 in «Foreign Address» column, indicates some client connected to it, which is netcat over here.UDP Client
Now that we have tested our server with netcat, its time to make a client and use it instead of netcat.
The program flow is like/* Simple udp client */ #include //printf #include //memset #include //exit(0); #include #include #define SERVER "127.0.0.1" #define BUFLEN 512 //Max length of buffer #define PORT 8888 //The port on which to send data void die(char *s) < perror(s); exit(1); >int main(void) < struct sockaddr_in si_other; int s, i, slen=sizeof(si_other); char buf[BUFLEN]; char message[BUFLEN]; if ( (s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) < die("socket"); >memset((char *) &si_other, 0, sizeof(si_other)); si_other.sin_family = AF_INET; si_other.sin_port = htons(PORT); if (inet_aton(SERVER , &si_other.sin_addr) == 0) < fprintf(stderr, "inet_aton() failed\n"); exit(1); >while(1) < printf("Enter message : "); gets(message); //send the message if (sendto(s, message, strlen(message) , 0 , (struct sockaddr *) &si_other, slen)==-1) < die("sendto()"); >//receive a reply and print it //clear the buffer by filling null, it might have previously received data memset(buf,'
/* Simple udp client */ #include //printf #include //memset #include //exit(0); #include #include #define SERVER "127.0.0.1" #define BUFLEN 512 //Max length of buffer #define PORT 8888 //The port on which to send data void die(char *s) < perror(s); exit(1); >int main(void) < struct sockaddr_in si_other; int s, i, slen=sizeof(si_other); char buf[BUFLEN]; char message[BUFLEN]; if ( (s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) < die("socket"); >memset((char *) &si_other, 0, sizeof(si_other)); si_other.sin_family = AF_INET; si_other.sin_port = htons(PORT); if (inet_aton(SERVER , &si_other.sin_addr) == 0) < fprintf(stderr, "inet_aton() failed\n"); exit(1); >while(1) < printf("Enter message : "); gets(message); //send the message if (sendto(s, message, strlen(message) , 0 , (struct sockaddr *) &si_other, slen)==-1) < die("sendto()"); >//receive a reply and print it //clear the buffer by filling null, it might have previously received data memset(buf,'\0', BUFLEN); //try to receive some data, this is a blocking call if (recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &si_other, &slen) == -1) < die("recvfrom()"); >puts(buf); > close(s); return 0; >
', BUFLEN); //try to receive some data, this is a blocking call if (recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &si_other, &slen) == -1) < die("recvfrom()"); >puts(buf); > close(s); return 0; >
Run the above program and it will ask for some message
$ gcc client.c -o client && ./client Enter message : happy happy
Whatever message the client sends to server, the same comes back as it is and is echoed.
Conclusion
UDP sockets are used by protocols like DNS etc. The main idea behind using UDP is to transfer small amounts of data and where reliability is not a very important issue. UDP is also used in broadcasting/multicasting.
When a file transfer is being done or large amount of data is being transferred in parts the transfer has to be much more reliable for the task to complete. Then the TCP sockets are used.
A Tech Enthusiast, Blogger, Linux Fan and a Software Developer. Writes about Computer hardware, Linux and Open Source software and coding in Python, Php and Javascript. He can be reached at [email protected] .
16 Comments
- Joe June 7, 2021 at 3:03 pm Hello. You seem to have double pasted the second code sample inside itself. THanks for the tutorial
- Silver Moon Post author August 14, 2018 at 4:04 pm i haven’t done sockets for a long time. right now i can think of using multiple threads do things in parallel.
so the main thread could do its background work, and an extra thread could listen to the udp port for incoming messages.
or the other way round.
but i am not sure if that is the best approach. there might be better alternatives.
- Bryan Kelly March 15, 2018 at 4:04 am And ncat used option -vv which on my Ubuntu system means verbose. The captured text does not have the verbose output. My system had five lines of information for each line of typed in data.
Still, I am new to Linux and Ubuntu and this is an unexpected cool way to test the server app.
Thank you.
Linux TCP/UDP Client & Server Connections using Netcat
Netcat is the most convenient TCP/UDP connection simulation tool that you can find for Linux terminal.
Here is a quick tutorial on simulating UDP and TCP connections on Linux terminal using Netcat (NCat). Netcat package comes bundled with the famous Linux port scanning tool: NMap.
Setup
// for RHEL/CentOS $ sudo yum install nmap -y // for Ubuntu/Debian $ sudo apt-get update $ sudo apt-get install nmap -y
- Next, you can setup one Netcat instance to listen to a certain port either via TCP/UDP transport protocol and setup another Netcat instance to establish a connection to it. Once the connection is established, both instances can send messages to other instances, which will work like a simple chat server and client.
Netcat options
- -l : set to listening state which create a simple HTTP server waiting for the incoming connections
- -p : define local port
- -u : set the UDP mode
UDP
- On a new terminal tab, run below command to create an instant UDP client communicating with the above server. You can input any simple text, click enter , and see it appearing in the server’s output stream.
$ nc -u localhost 30000 Hello world from client!
TCP
- On a new terminal tab, run below command to create an instant TCP client communicating with the above server. You can input any simple text, click enter , and see it appearing in the server’s output stream.
$ nc localhost 31000 Hello world from client!
Verify
// TCP $ netstat -nat | grep 31000 // UDP $ netstat -nau | grep 30000
- -v : enable verbose logs
- -n : show numeric host, port or user names
- -a : show both listening and non-listening (for TCP this means established connections) sockets
👉 Any questions? Please comment below.
Updated: January 02, 2020