In this test we run both the server and client program on the same host.
1. Firstly run the previous UDPReceiver program.
2. Then run the UDPSender program. The following screenshot shows both outputs.
Well, you have seen the issue here how the server/receiver can be in the 'listening' mode similar to the TCP counterpart. The recvfrom() part can be put in a loop to achieve this and/or for a better solution, you can use the select() function by setting the timeout and other simple features which provide more controls on the program behaviors. The code snippet is shown below.
int recvfromTimeOutUDP(SOCKET socket, long sec, long usec)
{
// Setup timeval variable
timeval timeout;
timeout.tv_sec = sec;
timeout.tv_usec = usec;
// Setup fd_set structure
fd_set fds;
FD_ZERO(&fds);
FD_SET(socket, &fds);
// Return value:
// -1: error occured
// 0: timed out
// > 0: data ready to be read
return select(0, &fds, 0, 0, &timeout);
}
SelectTiming = recvfromTimeOutUDP(s, 20, 30);
switch (SelectTiming)
{
case 0:
// Timed out, do whatever you want to handle this situation
break;
case -1:
// Error occured, maybe we should display an error message?
break;
default:
// Ok the data is ready, call recvfrom() to get it then
recvfrom(ReceivingSocket, ReceiveBuf, BufLength, 0, (SOCKADDR *)&SenderAddr, &SenderAddrSize);
}
A sample of the working program example that uses the select() function is given below. The project name is UDPServerVer2.
#include <winsock2.h>
#include <stdio.h>
// A sample of the select() return value
int recvfromTimeOutUDP(SOCKET socket, long sec, long usec)
{
// Setup timeval variable
struct timeval timeout;
struct fd_set fds;
timeout.tv_sec = sec;
timeout.tv_usec = usec;
// Setup fd_set structure
FD_ZERO(&fds);
FD_SET(socket, &fds);
// Return value:
// -1: error occured
// 0: timed out
// > 0: data ready to be read
return select(0, &fds, 0, 0, &timeout);
}
int main(int argc, char **argv)
{
WSADATA wsaData;
SOCKET ReceivingSocket;
SOCKADDR_IN ReceiverAddr;
int Port = 5150;
char ReceiveBuf[1024];
int BufLength = 1024;
SOCKADDR_IN SenderAddr;
int SenderAddrSize = sizeof(SenderAddr);
int ByteReceived = 5, SelectTiming, ErrorCode;
char ch = 'Y';
// Initialize Winsock version 2.2
if( WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
{
printf(Server: WSAStartup failed with error %ld\n, WSAGetLastError());
return -1;
}
else
printf(Server: The Winsock DLL status is %s.\n, wsaData.szSystemStatus);
// Create a new socket to receive datagrams on.
ReceivingSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (ReceivingSocket == INVALID_SOCKET)
{
printf(Server: Error at socket(): %ld\n, WSAGetLastError());
// Clean up
WSACleanup();
// Exit with error
return -1;
}
else
printf(Server: socket() is OK!\n);
// Set up a SOCKADDR_IN structure that will tell bind that we
// want to receive datagrams from all interfaces using port 5150.
// The IPv4 family
ReceiverAddr.sin_family = AF_INET;
// Port no. 5150
ReceiverAddr.sin_port = htons(Port);
// From all interface (0.0.0.0)
ReceiverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
// Associate the address information with the socket using bind.
// At this point you can receive datagrams on your bound socket.
if (bind(ReceivingSocket, (SOCKADDR *)&ReceiverAddr, sizeof(ReceiverAddr)) == SOCKET_ERROR)
{
printf(Server: bind() failed! Error: %ld.\n, WSAGetLastError());
// Close the socket
closesocket(ReceivingSocket);
// Do the clean up
WSACleanup();
// and exit with error
return -1;
}
else
printf(Server: bind() is OK!\n);
// Some info on the receiver side...
getsockname(ReceivingSocket, (SOCKADDR *)&ReceiverAddr, (int *)sizeof(ReceiverAddr));
printf(Server: Receiving IP(s) used: %s\n, inet_ntoa(ReceiverAddr.sin_addr));
printf(Server: Receiving port used: %d\n, htons(ReceiverAddr.sin_port));
printf(Server: I\'m ready to receive a datagram...\n);
SelectTiming = recvfromTimeOutUDP(ReceivingSocket, 10, 0);
switch (SelectTiming)
{
case 0:
// Timed out, do whatever you want to handle this situation
printf(Server: Timeout lor while waiting you bastard client!...\n);
break;
case -1:
// Error occured, maybe we should display an error message?
// Need more tweaking here and the recvfromTimeOutUDP()...
printf(Server: Some error encountered with code number: %ld\n, WSAGetLastError());
break;
default:
{
while (1)
{
// Call recvfrom() to get it then display the received data...
ByteReceived = recvfrom(ReceivingSocket, ReceiveBuf, BufLength, 0, (SOCKADDR *)&SenderAddr, &SenderAddrSize);
if ( ByteReceived > 0 )
{
printf(Server: Total Bytes received: %d\n, ByteReceived);
printf(Server: The data is \%s\\n, ReceiveBuf);
}
else if ( ByteReceived <= 0 )
printf(Server: Connection closed with error code: %ld\n, WSAGetLastError());
else
printf(Server: recvfrom() failed with error code: %d\n, WSAGetLastError());
// Some info on the sender side
getpeername(ReceivingSocket, (SOCKADDR *)&SenderAddr, &SenderAddrSize);
printf(Server: Sending IP used: %s\n, inet_ntoa(SenderAddr.sin_addr));
printf(Server: Sending port used: %d\n, htons(SenderAddr.sin_port));
}
}
}
// When your application is finished receiving datagrams close the socket.
printf(Server: Finished receiving. Closing the listening socket...\n);
if (closesocket(ReceivingSocket) != 0)
printf(Server: closesocket() failed! Error code: %ld\n, WSAGetLastError());
else
printf(Server: closesocket() is OK...\n);
// When your application is finished call WSACleanup.
printf(Server: Cleaning up...\n);
if(WSACleanup() != 0)
printf(Server: WSACleanup() failed! Error code: %ld\n, WSAGetLastError());
else
printf(Server: WSACleanup() is OK\n);
// Back to the system
return 0;
}
When we run the UDP receiver/server program, while there is no client connection in 10 seconds, the program terminates.
The following screenshot shows that when there are connections, the socket keeps opening and listening. We test the same client (UDPSender), by sending multiple UDP datagrams. You may want to test this program with the client 'connected' or sending the datagram from different hosts, in private or public network. The following screenshot shows the sender output samples.
The following screenshot shows the receiver sample output. Keep in mind that both receiver and sender programs were run on the same host.