Winsock 1 - UDP Client 
The UDP Client tutorial demonstrates how to set up a Client application and communicate with a Server via UDP.  This application needs to be run in conjunction with UDP Server.  Together, these two apps create a simple connection and can facilitate one-way communication between two hosts.  This tutorial explains the fundamental mechanics involved with a UDP Client.  Subsequent tutorials will assume an understanding of these concepts. 

 


Downloads 
Program Only  UDPClient.exe.  No source files. 
Program and Source Files  UDPClient source files, project files and executable. 
Note:  You must unzip these files with subdirectories!  (example:  "pkunzip -d ws1_full.zip") 


Project Files 


res\client.ico 
res\tcpclient.rc2 
resource.h 
stdafx.cpp 
stdafx.h 
UDPClient.aps 
UDPClient.clw 
UDPClient.cpp 
UDPClient.h 
UDPClient.mak 
UDPClient.mdp 
UDPClient.ncb 
UDPClient.rc 
UDPClientdlg.cpp 
UDPClientdlg.h 

All of these files were generated by App Wizard, using a the dialog-based application template.  Only the files UDPClientDlg.cpp and UDPClientDlg.h were added to for the tutorial code.  One line was added to stdafx.h to enable socket support.  With the exception of the resource files, no other files were changed.  See the section below for discussions on the socket code. 

Discussion 


To understand how this application works, all we need to do is take a detailed look at the file UDPClientDlg.cpp.  This section will also briefly introduce some MFC programming concepts, in case you are unfamiliar with them.  But before we can do anything with sockets, we need to include the Winsock header files into the project.  This is done in stdafx.h

#include <afxsock.h>  // MFC socket extensions 

This is the last line stdafx.h.  It was added manually to allow us to use the Winsock data structures and APIs in our code.  Including this line in stdafx.h lets us use Winsock API's anywhere in our project.  Now, let's take a look at UDPClientDlg.cpp

BEGIN_MESSAGE_MAP(CUDPClientDlg, CDialog) 
    //{{AFX_MSG_MAP(CUDPClientDlg) 
    ON_WM_SYSCOMMAND() 
    ON_WM_PAINT() 
    ON_WM_QUERYDRAGICON() 
    ON_BN_CLICKED(IDC_BN_QUIT, OnBnQuit) 
    ON_BN_CLICKED(IDC_BN_SEND, OnBnSend) 
    //}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
This is the Message Map.  This is simply used to associated functions with user-interface events, or "messages."  The line that we care about in the Message Map is: 
    ON_BN_CLICKED(IDC_BN_SEND, OnBnSend) 
This line tells us that the function  OnBnSend() will be called when the user hits the "Send" button.  As it turns out, all the sockets processing happens in this function. 

CUDPClientDlg::CUDPClientDlg(CWnd* pParent /*=NULL*/) 
 : CDialog(CUDPClientDlg::IDD, pParent) 
{ 
    ... 
} 
This is the a standard C++ constructer, no changes are needed. 

CUDPClientDlg::~CUDPClientDlg() 
{ 
    RemoveSockets(); 
} 
This is a standard C++ destructer.  I felt that it was a good place to call our sockets cleanup routine RemoveSockets().  This will be explained more below when socket initialization is discussed. 

void CUDPClientDlg::DoDataExchange(CDataExchange* pDX) 
{ 
    ... 
} 
This function, DoDataExchange(), is where MFC associates C++ class members with their corresponding user interface control.  All of this generated by Class Wizard, so no changes were necessary. 

BOOL CUDPClientDlg::OnInitDialog() 
{ 
    char  buf[255]; 
    ... 
//-- Initialization 
    InitSockets_1_1(); 
    m_edLocalName.SetWindowText(GetHostName(buf, 255)); 
    m_edLocalIP.SetWindowText(IPString(uGetLocalIP(), buf, 255)); 
    m_edMessage.SetWindowText("This is a UDP Message."); 
    m_edServerPort.SetWindowText("4000"); 
  
    return TRUE;  // return TRUE  unless you set the focus to a control 
} 
This function, OnInitDialog(), is called exactly one time, precisely when the dialog starts up.  It is a handy place to do all of our initialization.  We can not do this initialization in the constructer because the constructor is called before some of our members are created and attached to their corresponding user-interface controls.  Most of the code in this function is standard MFC fare. The lines that we are interested in for this tutorial are at the end. 

The first call we make is InitSockets_1_1().  This function determines if the host is capable of supporting Winsock 1.1 functionality.  If it is, this function enables the host to use the Winsock APIs.  Otherwise, the function fails.  If this function succeeds, you must call RemoveSockets() when you are done with the Winsock APIs.  This function is one of our general winsock utility functions.  Refer to Quinn & Shute pp. 320 - 322. 

After InitSockets_1_1(), we simply set up a few of the user-interface controls with some desired values.  The functions GetHostName(), IPString() and uGetLocalIP() are all general winsock utility functions. 

void CUDPClientDlg::OnSysCommand(UINT nID, LPARAM lParam) 
{ 
    ... 
} 

void CUDPClientDlg::OnPaint()  
{ 
    ... 
} 

HCURSOR CUDPClientDlg::OnQueryDragIcon() 
{ 
    ... 
} 
These function are more standard MFC fare.  They were created by App Wizard. 

void CUDPClientDlg::OnBnQuit()  
{ 
    EndDialog(0); 
} 
This function was added manually.  It's sole purpose is to end the application when the user hits the "Quit" button. 

Finally, this function is where the core functionality lies. 
void CUDPClientDlg::OnBnSend()  
{ 
We need to declare some variables.  We need a destination address to fill in, addr_Dest.  We need a socket, sock_Send.  We need two string buffers for the message we are sending and the destination IP address, szMessage[256] and szDestIP[20].  We need a port number to send on, destport.  And finally we need a temporary string to hold some values for us, csTemp
    SOCKADDR_IN    addr_Dest; 
    SOCKET         sock_Send; 
    char           szMessage[256], szDestIP[20]; 
    short          destport; 
    CString        csTemp; 

First, get the message to send from the edit box.  Then copy it into szMessage[256]
//-- Prepare the message 
    m_edMessage.GetWindowText(csTemp); 
    if (csTemp.IsEmpty()) 
    { 
        AfxMessageBox("Please enter a message."); 
        return; 
    } 
    sprintf(szMessage, csTemp.GetBuffer(0)); 
    csTemp.ReleaseBuffer(-1); 

Now get the destination IP address and copy it into szDestIP[20]
//-- Get the IP addres to send to 
    m_edServerName.GetWindowText(csTemp); 
    if (csTemp.IsEmpty()) 
    { 
        AfxMessageBox("Please enter a valid host name or IP address"); 
        return; 
    } 
    strcpy(szDestIP, csTemp.GetBuffer(0)); 
    csTemp.ReleaseBuffer(-1); 

Likewise, get the port number to send on and put it in destport
//-- Get the port to send to 
    m_edServerPort.GetWindowText(csTemp); 
    destport = atoi(csTemp.GetBuffer(0)); 
    csTemp.ReleaseBuffer(-1); 
    if (destport < 1) 
    { 
        AfxMessageBox("Please enter a valid UDP destination port"); 
        return; 
    } 

Now, create a TCP socket with the socket() function.  In winsock using TCP/IP, the first and last parameters will always be AF_INET and 0.  The middle parameter determines whether a TCP or UDP socket gets created.  Using SOCK_DGRAM will create a UDP socket.  Refer to Quinn & Shute pp. 50 - 53. 
//-- Create TCP socket 
    if ((sock_Send = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 
        AfxMessageBox("Error:  socket() failed."); 

Now fill in the message destination address structure.  The function inet_addr() converts a text string with a dotted decimal IP address into the 4 byte form that the network layer understands.  The function htons() makes sure that the port number is stored in the proper network byte order.  Refer to Quinn & Shute pp. 54 - 55. 
//-- Fill in target addr 
    memset((char *) &addr_Dest, 0, sizeof(addr_Dest)); 
    addr_Dest.sin_family      = AF_INET; 
    addr_Dest.sin_addr.s_addr = inet_addr(szDestIP); 
    addr_Dest.sin_port        = htons(destport);  

We don't need to connect to the Server for a UDP message.  Just go ahead and try to send it to the Server's address.  Refer to Quinn & Shute pp. 64 - 66. 
//-- Send it 
    if (sendto(sock_Send, szMessage, 256, 0, (sockaddr*)&addr_Dest, sizeof(addr_Dest)) == SOCKET_ERROR) 
        AfxMessageBox("Error:  sendto() failed."); 

Now we are done with this socket, so we need to close it.  Refer to Quinn & Shute pp. 70 - 71. 
    closesocket(sock_Send); 
} 


Back to Winsock 1 Page 
Back to Winsock Tutorials Main Page