Click here to Skip to main content
15,887,302 members
Articles / Programming Languages / C++

Sending & Receiving UDP Datagrams with MFC's CAsyncSocket C++ Class

Rate me:
Please Sign up or sign in to vote.
3.03/5 (18 votes)
5 Dec 2006Public Domain2 min read 116.9K   45   9
A simple example to show the use of the MFC CAsyncSocket class to send and receive UDP datagrams

Introduction

The following code is intended to provide a very simple example of how to use Microsoft MFC’s CAsyncSocket class to send and receive UDP datagrams.

I was unable to find a simple example of how to use CAsynSocket to send & receive UDP datagrams, so I created my own. I thought others might find it useful. The example shown creates two independent send sockets & a single receiver socket, that will receive data from both senders.

Using the Code

To reduce clutter, I have:

  1. included only code relevant to the UDP communications (all socket class code is included, much application code is not).
  2. created separate classes to deal with sending UDP & receiving UDP

The code snippets of my test applications main dialog, UdpTestAppDlg (.cpp & .h), show how to use the simple UdpReceiveSocket & UdpSendSocket classes that I have provided here. The example code shown creates two independent send sockets & a single receiver socket. The receive socket will receive datagrams from both senders.

The rudimentary error handling that is included is sufficient to highlight the commonest socket problems.

C++
// Receiving Socket Class definition
#pragma once
#include <afxtempl.h>

// UdpReceiveSocket command target
class UdpReceiveSocket : public CAsyncSocket
{
      void OnReceive(int nErrorCode);
public:
      UdpReceiveSocket();
      virtual ~UdpReceiveSocket();
};
C++
// Receiving Socket Class implementation
// UdpReceiveSocket.cpp : implementation file
//
#include "stdafx.h"
#include "UdpTestApp.h"
#include "UdpReceiveSocket.h"

// UdpReceiveSocket
UdpReceiveSocket::UdpReceiveSocket()
{
      // Just specify input PORT#, local machine is assumed
      BOOL bRet = Create(9122,SOCK_DGRAM,FD_READ);
      if (bRet != TRUE)
      {
             UINT uErr = GetLastError();
             TCHAR szError[256];
             wsprintf(szError, "Server Receive Socket Create() failed: %d", uErr);
             AfxMessageBox(szError);
      }
}

UdpReceiveSocket::~UdpReceiveSocket()
{
}

// UdpReceiveSocket member functions
void UdpReceiveSocket::OnReceive(int nErrorCode)   
{
  static int i=0;

  i++;

  TCHAR buff[4096];
  int nRead;

  CString strSendersIp;

  UINT uSendersPort;

  // Could use Receive here if you don't need the senders address & port
  nRead = ReceiveFromEx(buff, 4096, strSendersIp, uSendersPort); 

  switch (nRead)
  {
  case 0:       // Connection was closed.
     Close();      
     break;
  case SOCKET_ERROR:
     if (GetLastError() != WSAEWOULDBLOCK) 
     {
        AfxMessageBox ("Error occurred");
        Close();
     }
     break;
  default: // Normal case: Receive() returned the # of bytes received.
     buff[nRead] = 0; //terminate the string (assuming a string for this example)
     CString strReceivedData(buff);       // This is the input data    
  }
  CAsyncSocket::OnReceive(nErrorCode);
}
C++
// Sending Socket Class definition
#pragma once
// UdpSendSocket
class UdpSendSocket : public CAsyncSocket
{
      bool m_bReadyToSend;
public:
      UdpSendSocket();
      virtual ~UdpSendSocket();
      //
      virtual bool Send(const void* lpBuf, int nBufLen ); 
      virtual void OnSend(int nErrorCode);
};
C++
// Sending Socket Class implementation
// UdpSendSocket.cpp : implementation file
//

#include "stdafx.h"
#include "UdpTestApp.h"
#include "UdpSocket.h"

// UdpSendSocket
UdpSendSocket::UdpSendSocket():m_bReadyToSend(false)
{
      // Create a socket for sending
      // **DO NOT SPECIFY DESTINATION ADDRESS HERE**
      BOOL bRet = Create(0,SOCK_DGRAM,FD_WRITE);
      if (bRet != TRUE)
      {
             UINT uErr = GetLastError();
             TCHAR szError[256];
             wsprintf(szError, "Send Socket Create() failed: %d", uErr);
             AfxMessageBox(szError);
      }
}

UdpSendSocket::~UdpSendSocket()
{
}

// UdpSendSocket member functions
void UdpSendSocket::OnSend(int nErrorCode)
{
  m_bReadyToSend = true;    // The socket is now ready to send
  CAsyncSocket::OnSend(nErrorCode);
}

bool UdpSendSocket::Send(const void* lpBuf, int nBufLen)
{
      if ( ! m_bReadyToSend )
             return(false);
      m_bReadyToSend = false;
      int dwBytes;
      CAsyncSocket *paSocket = this;
      // Specify destination here (IP number obscured - could use computer name instead)
      if ((dwBytes = CAsyncSocket::SendToEx
	((LPCTSTR)lpBuf,nBufLen,9122,"172.XX.XX.XXX")) == SOCKET_ERROR)
      {
             UINT uErr = GetLastError();
             if (uErr != WSAEWOULDBLOCK) 
             {
                    TCHAR szError[256];
                    wsprintf(szError, "Server Socket failed to send: %d", uErr);
                    AfxMessageBox(szError);
             }
             return(false);
      }
      return(true);
C++
// UdpTestAppDlg.cpp
void CUdpTestAppDlg::SendUdpDatagram()
{
CString strTestMessage = "Hello World";
m_ussSendSocket1.Send(strTestMessage.GetBuffer(),strTestMessage.GetLength()+1);
m_ussSendSocket2.Send(strTestMessage.GetBuffer(),strTestMessage.GetLength()+1);
}
C++
// UdpTestAppDlg.h : header file
//

#pragma once
#include "UdpReceiveSocket.h"
#include "UdpSendSocket.h"

// CUdpTestAppDlg dialog
class CUdpTestAppDlg : public CDialog
{
…
// Implementation
protected:
      HICON m_hIcon;
      UdpReceiveSocket       m_ursReceiveSocket;       // Receive socket
      UdpSendSocket              m_ussSendSocket1;     // Just holds Ip & port # for send
      UdpSendSocket              m_ussSendSocket2;     // Just holds Ip & port # for send
      void SendUdpDatagram();
…
};//

Points of Interest

It turns out that using CAsyncSocket to send & receive UDP messages is quite straightforward, once you know how. The Microsoft documentation covers both TCP & UDP, which tends to obscure how simply this can be achieved. The other problem, lack of a simple example, has hopefully been addressed here.

The example above sends & receives strings. It is a good idea to keep UDP messages small for a number of reason, however it is a simple matter to send a buffers of bytes (e.g. based on a byte-aligned structure). ALthough non-essential in this example, it is also good practice to convert Microsoft Windows Intel alignment to network byte order before sending & to convert back when processing received data, using functions like ntohl().

License

This article, along with any associated source code and files, is licensed under A Public Domain dedication


Written By
Web Developer
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionGreat !! Pin
ur_special21-May-19 17:28
ur_special21-May-19 17:28 
Questionwsastartup Pin
bkelly1320-Mar-17 7:10
bkelly1320-Mar-17 7:10 
AnswerRe: wsastartup Pin
Rick York20-Mar-17 8:12
mveRick York20-Mar-17 8:12 
QuestionDownload? Pin
ulatekh11-Jan-16 4:59
ulatekh11-Jan-16 4:59 
BugUsing 'OnSend' with m_bReadyToSend is buggy Pin
CarstenBPoulsen23-Feb-14 10:08
CarstenBPoulsen23-Feb-14 10:08 
OnSend gets called only once after a successful connection, and it is not called again until after a call to Send() returns an error. At some point in time after the error, OnSend will get called when it's safe to call Send() again. That's the way Send() in winsock is designed.

So your code will only be able to send 'Hello World' twice, i.e. once for each UdpSendSocket instantiation (m_ussSendSocket1 & ...2).

The code will work if the lines
if ( ! m_bReadyToSend )
return(false);
are commented out.
GeneralError Comming while creation Pin
buntyrolln5-Jun-08 19:34
buntyrolln5-Jun-08 19:34 
GeneralRe: Error Comming while creation Pin
Zeek211-Jun-08 6:07
Zeek211-Jun-08 6:07 
AnswerRe: Error Comming while creation Pin
buntyrolln11-Jun-08 21:46
buntyrolln11-Jun-08 21:46 
GeneralRe: Error Comming while creation Pin
shine joseph2-Sep-08 3:45
shine joseph2-Sep-08 3:45 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.