Click here to Skip to main content
Click here to Skip to main content

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

, 5 Dec 2006
Rate this:
Please Sign up or sign in to vote.
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.

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

// UdpReceiveSocket command target
class UdpReceiveSocket : public CAsyncSocket
{
      void OnReceive(int nErrorCode);
public:
      UdpReceiveSocket();
      virtual ~UdpReceiveSocket();
};
// 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);
}
// 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);
};
// 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);
// 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);
}
// 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

About the Author

Member 1385698
Web Developer
United Kingdom United Kingdom
No Biography provided

Comments and Discussions

 
BugUsing 'OnSend' with m_bReadyToSend is buggy PinmemberCarstenBPoulsen23-Feb-14 10:08 
GeneralError Comming while creation Pinmemberbuntyrolln5-Jun-08 19:34 
GeneralRe: Error Comming while creation PinmemberMember 138569811-Jun-08 6:07 
AnswerRe: Error Comming while creation Pinmemberbuntyrolln11-Jun-08 21:46 
GeneralRe: Error Comming while creation Pinmembershine joseph2-Sep-08 3:45 

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

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

| Advertise | Privacy | Mobile
Web03 | 2.8.140721.1 | Last Updated 5 Dec 2006
Article Copyright 2006 by Member 1385698
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid