This project consists of a simple UDP server and client programs. If you've never written a program that uses UDP, this is an ideal starting project. The server runs on a local computer, waiting for a datagram request from a remote computer asking for the server's current time. The server then returns its current time to the client, which in turn displays it.
UDP stands for User Datagram Protocol. The client sends a datagram to the server, which then processes the information and returns a response. This article demonstrates how to use the
The server program
The server program is a simple UDP server that waits for the datagram from clients. When it receives a datagram containing the text "GET TIME\r\n", it returns the current server's time to the client.
Opening the Windows connection
Before calling any socket functions, it is necessary to first open the Windows connection. This is done with the
/* Open windows connection */
if (WSAStartup(0x0101, &w) != 0)
fprintf(stderr, "Could not open Windows connection.\n");
The hexadecimal number
0x0101 is the version of WinSock to use, and the variable
w is a structure of
Opening a datagram socket
The next step is to open a datagram socket for UDP. This is done with the
socket function, which returns a socket descriptor.
/* Open a datagram socket */
sd = socket(AF_INET, SOCK_DGRAM, 0);
if (sd == INVALID_SOCKET)
fprintf(stderr, "Could not create socket.\n");
AF_INET specifies the family to use, and
SOCK_DGRAM tells the function we want to use UDP instead of TCP/IP.
Setting up the server information
After this, it is necessary to fill in some information about the server in a
struct of type
sockaddr_in. First, the memory in the
struct is cleared out. Then the family of the server is set, which is always
AF_INET. Then the port number is set using the
htons function. Depending on the command line parameters entered, the server will either try to get its own IP address, which is the preferred method of operation, or if that doesn't work, it can be specified manually. To automatically get the address of the server computer, the
gethostname function is called, and then the function
gethostbyname returns a pointer to a
struct of type
hostent. Finally, each component of the address in xxx.xxx.xxx.xxx form is copied to the
/* Clear out server struct */
memset((void *)&server, '\0', sizeof(struct sockaddr_in));
/* Set family and port */
server.sin_family = AF_INET;
server.sin_port = htons(port_number);
/* Set address automatically if desired */
if (argc == 2)
/* Get host name of this computer */
hp = gethostbyname(host_name);
/* Check for NULL pointer */
if (hp == NULL)
fprintf(stderr, "Could not get host name.\n");
/* Assign the address */
server.sin_addr.S_un.S_un_b.s_b1 = hp->h_addr_list;
server.sin_addr.S_un.S_un_b.s_b2 = hp->h_addr_list;
server.sin_addr.S_un.S_un_b.s_b3 = hp->h_addr_list;
server.sin_addr.S_un.S_un_b.s_b4 = hp->h_addr_list;
/* Otherwise assign it manually */
server.sin_addr.S_un.S_un_b.s_b1 = (unsigned char)a1;
server.sin_addr.S_un.S_un_b.s_b2 = (unsigned char)a2;
server.sin_addr.S_un.S_un_b.s_b3 = (unsigned char)a3;
server.sin_addr.S_un.S_un_b.s_b4 = (unsigned char)a4;
a4 are the components of the server's address in xxx.xxx.xxx.xxx form as typed on the command line.
Binding the address to the socket
The next step is to bind the server's address to the socket created by the
socket function. This is done using the
bind function, which returns -1 if there is an error.
/* Bind address to socket */
if (bind(sd, (struct sockaddr *)&server,
sizeof(struct sockaddr_in)) == -1)
fprintf(stderr, "Could not bind name to socket.\n");
Getting the datagram from the client
The server is now ready to listen for datagrams from clients. This is done using the
buffer is the buffer to store the datagram received, and
BUFFER_SIZE is the maximum number of bytes to receive.
client is a
struct of type
sockaddr_in that contains information about the client sending the datagram, including the client's address.
client_length = (int)sizeof(struct sockaddr_in);
/* Receive bytes from client */
bytes_received = recvfrom(sd, buffer, BUFFER_SIZE, 0,
(struct sockaddr *)&client, &client_length);
if (bytes_received < 0)
fprintf(stderr, "Could not receive datagram.\n");
Sending back a response
Once the datagram has been received by the server, the server compares the information in the datagram to the string "GET TIME\r\n". If these strings match, then the server returns the time. Otherwise, the request is discarded as an invalid request. The time is sent back to the client using the
/* Check for time request */
if (strcmp(buffer, "GET TIME\r\n") == 0)
/* Get current time */
current_time = time(NULL);
/* Send data back */
if (sendto(sd, (char *)¤t_time,
(struct sockaddr *)&client, client_length) !=
fprintf(stderr, "Error sending datagram.\n");
After this, the server returns in an infinite loop back to the
The client program
The client program is a simple UDP client that sends a request to the server to get the current time and receives the time back. First, the Windows connection is opened. Then a socket is opened. Next the address of the server is copied into the
struct. This code is very similar to the code for the server.
Getting the address of the client
In a UDP client, it is necessary to know the IP address of the client computer. This can be done automatically, or manually assigned by a command line switch. The code is almost identical to the code to assign the address to the server, except that the port number for the client is set to zero
client.sin_port = htons(0);, where
client is a
struct of type
Binding the client address to the socket
The next step is to bind the client address to the socket. This code is almost identical to the code for the server.
Transmitting the request to get the time
Now it is time to send the request to the server for the current time. The
sendto function is used to do this:
/* Tranmsit data to get time */
server_length = sizeof(struct sockaddr_in);
if (sendto(sd, send_buffer, (int)strlen(send_buffer) + 1,
0, (struct sockaddr *)&server, server_length) == -1)
fprintf(stderr, "Error transmitting data.\n");
send_buffer is a string containing the text
"GET TIME\r\n" terminated by a null terminator.
Receiving the time
After the request for the time has been sent, a response from the server will be sent back. This is done with the
/* Receive time */
if (recvfrom(sd, (char *)¤t_time,
(struct sockaddr *)&server,
&server_length) < 0)
fprintf(stderr, "Error receiving data.\n");
current_time is a
time_t variable that stores the time.
Closing the socket and cleaning Up
The program is almost finished. The last step is to close the socket and Windows connection. The socket is closed with the
closesocket function, and
WSACleanup is called to close the Windows connection:
Using the server program
The syntax for the server program is
timeserv [server_address] port. The
port is the port number to run the server on. It is recommended that you choose a port number above 1023, as the lower port numbers may be assigned to other protocols. The optional
server_address parameter is the local IP address of the server computer entered in xxx.xxx.xxx.xxx form. If this parameter is omitted, the program will attempt to automatically get the address. Most of the time this works fine, but if you have more than one network connection, such as an Ethernet card and wireless networking card, the program may choose the wrong one. In this case, type
ipconfig at the command prompt to determine your address and enter it on the command line. For example, to run the program with automatic local address generation on port 5000, you would type:
timeserv 5000, and to run it on a computer with a local address of 192.168.1.102, you would type
timeserv 192.168.1.102 5000. To quit the server program, hold down the CTRL key and press C.
Using the client program
Before starting the client program, first make sure the server program is running on the server computer. The syntax for the client program is
timecli server_address port [client_address]. The
server_address is the address in xxx.xxx.xxx.xxx form that the server computer is running on. The port parameter is the port that the server is running on. The optional
client_address parameter overrides the automatic local address generation for the client computer and is similar in operation to the server program listed above. For example, to connect to a server with an address of 192.168.1.102 running on port 5000, you would type
timecli 192.168.1.102 5000.
Points of interest
Firewall and anti-virus software
Some firewall and anti-virus programs may not allow you to run the server and/or client program on your computer. This is just their attempt to protect you from spyware. These programs may by mistake identify this project as some sort of spyware. If your firewall or anti-virus program blocks either one of these programs, you may have to temporarily disable them. Be sure, however, to turn them back on when you're done using these programs.
Linking the code
When you compile the source code files, be sure to link them with the library file wsock32.lib. Otherwise, the linker will generate a bunch of errors saying that there are undefined functions.
Why did I choose to write this program in C?
A question I will probably be asked is, "Why did you write this program in C instead of C++?". The answer is simple. The point of this program is to show the basic framework of WinSock programming, not to give the smallest and most up-to-date code. That's why I chose not to implement the program with the MFC
CSocket class, for example. Don't worry, however, the source code will still compile with a C++ compiler. I wanted to demonstrate the use of basic functions such as
sendto. I originally learned socket programming on a UNIX system and want programmers from that environment to see how similar functions can be used in Windows programming. This is a basic example program for beginners in WinSock programming, not a program intended for advanced programmers, who probably already know all this stuff anyway.
Running the programs on a computer with no network connection
It is possible to test out this server and client on a computer that doesn't have any network connections by using the loopback address. The loopback address is 127.0.0.1 and is not associated with any network hardware. To run the server on the loopback address, type
timeserv 127.0.0.1 5000, and to run the client, type
timecli 127.0.0.1 5000 127.0.0.1 on the same computer.