Solved

CAsyncSocket

Posted on 2001-07-22
27
2,453 Views
Last Modified: 2013-11-20
Hi, how do I create a blocking CAsyncSocket? When I try to ReceiveFrom, it complains about WSAEWOULDBLOCK, meaning ReceiveFrom is blocking but the socket is not, but I don't know how to make the socket blocking.

I read the http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/HTML/_core_windows_sockets.3a_.blocking.asp, it says I should avoid blocking operations. My another question is, how do I use the callback OnReceive in a seperate thread? I know I can redefine it, but I don't know how to make the framework to call it.

I want to use a seperate thread to receive fr the socket.
0
Comment
Question by:hoooi
  • 9
  • 9
  • 7
  • +2
27 Comments
 
LVL 32

Expert Comment

by:jhance
Comment Utility
CAsyncSockets are, by nature, non-blocking.  

If you want blocking, use CSocket instead.
0
 
LVL 49

Expert Comment

by:DanRollins
Comment Utility
You will run into problems if you create the socket in one thread and then receive from it in another.

Use a separate thread to both create the socket and to and receive from it.

-- Dan
0
 
LVL 9

Expert Comment

by:ShaunWilde
Comment Utility
use CAsyncSocket for datagram type socket connections
use CSocket for stream type socket connections

for multithreading the following articles will be of use


http://support.microsoft.com/support/kb/articles/Q175/6/68.ASP

http://support.microsoft.com/support/kb/articles/Q214/3/96.ASP

and

http://msdn.microsoft.com/library/devprods/vs6/visualc/vcmfc/_mfc_csocket.3a3a.attach.htm



0
 

Expert Comment

by:ahmadrazakhan
Comment Utility
WOULDBLOCK error is in case when there is some very fast data arrival at socket, if u retry Receivefrom after few seconds u will read the data.
Actually the socket buffers r full if data arrives at great speed, as our application sometimes cant process data at speed at which it is coming from network, WOULDBLOCK error is there.
0
 
LVL 9

Expert Comment

by:ShaunWilde
Comment Utility
if the data is arriving very fast then you should receive the data on one thread and then pas the data to be processed onto another thread.

> WOULDBLOCK error is in case when there is some very fast data arrival at socket, if u retry Receivefrom
after few seconds u will read the data.

you get the error because it is telling you that there isn't enough data to read in that operation and that to to read what you wnat would mean that it would have to wait (block) for the rest to arrive - when you try later the daat is there and you can receive the data.

use an Onreceive handler - derive a class from C(Async)Socket and override the OnReceive handler - and do all you receving in there - design your packets such that you can peek the first few bytes and determine the packet type/size much easier fo handing off the data to other threads etc if you know what data it is you want processing and how muc you expect to have before passing it over

0
 

Expert Comment

by:ahmadrazakhan
Comment Utility
Derive a class from CWinThread and use AfxBeginThread, to trigger separate thread. As data arrives in Onreceive, send incoming dat to new thread for processing. This way Onreceive will be again ready for incoming messages
0
 
LVL 9

Expert Comment

by:ShaunWilde
Comment Utility
> Derive a class from CWinThread and use AfxBeginThread

you only need this type of thread if you intend on using MFC objects that require it eg CWnd CSocket
0
 

Author Comment

by:hoooi
Comment Utility
Thank you all. Over the weekend, I've tried all kinda solutions. I tried:
AsyncSelect(0), IOCtl(FIONBIO, &value) value is 0, derive a class fr CWinThread following the example http://support.microsoft.com/support/kb/articles/Q175/6/68.ASP, and a lot more, and I always get different errors. Let me explain what I use socket for.
1) When I launch my app, I broadcast a message, I will need to receive response back, but I will worry about it later.
2) My app will then start a thread that listen to messages fr #1 fr other machines that do the same. Whenever a message fr #1 is received, process something, then reply back only to the machine that broadcasts.
3) The port number should remain the same everytime the app starts. I don't know if the broadcast or receive uses it though.

The reason I don't use OnReceive (I tried before) is because I simply don't know how it can be trigerred. When I broadcast, I should be able to receive the my own message, and I don't see it happen in OnReceive. I read that I will need GetMessage, TranslateMessage and DispatchMessage, and it only works if you have dialog/window, but I don't know how and it cannot involve dialog. The callback doesn't quite work for me. So, I'm trying to convert ReceiveFrom to blocking, but unsuccessful.

Here are my classes:

class CMySocket : public CAsyncSocket
{
protected:
      BOOL                  onLAN;
public:
      CMySocket ();
      virtual ~CMySocket ();
      void BroadcastMsg(Message inMsg);
      void WriteMsg(Message *outMsg, sockaddr_in* lpSockAddr);
      void DetectMsg();
      virtual void OnReceive(int nErrorCode);
};

#include <stdafx.h>
#include "CMySocket.h"

CMySocket::CMySocket () : CAsyncSocket() {
      BOOL      bInit;
      BOOL      bCreate;
      BOOL      bSetOpt;
      BOOL    bSe
      BOOL      broadcastValue = TRUE;
      
      onLAN = TRUE;

      bInit = AfxSocketInit(NULL);
      bCreate = Create(PORT_NUM, SOCK_DGRAM);
      bSetOpt = SetSockOpt(SO_BROADCAST, &broadcastValue, sizeof(BOOL));
      BOOL bSe = AsyncSelect(0);
}

CMySocket::~CMySocket() {}

void CMySocket::BroadcastMsg(Message outMsg) {
      BOOL retcode;
      // NULL == broadcast
      retcode = SendTo((void*)&outMsg, sizeof(NLDMessage), PORT_NUM, NULL, 0);

      if (retcode == SOCKET_ERROR) {
            int errcode = 0;
            errcode = GetLastError();
      }
}

void CMySocket::WriteMsg(Message *outMsg, sockaddr_in* lpSockAddr) {
      BOOL retcode;
      // This is used when replying to a specific machine
      retcode = SendTo((void*)outMsg, sizeof(NLDMessage), (SOCKADDR *)lpSockAddr, sizeof (lpSockAddr), 0);
}

void CMySocket::DetectMsg()
{
      DWORD value = 0;
      BOOL bIO = IOCtl(FIONBIO, &value);
      
      if (bIO == 0) {
            int errcode = 0;
            errcode = GetLastError();
      }

      if (onLAN == TRUE) {
            Message      message, outMsg;
            sockaddr_in senderAddr;
            int                  addrLen;
            int                  mesgLen;
            int                  count;

            memset (&message, 0, sizeof (Message));
            mesgLen = sizeof(Message);

            memset (&senderAddr, 0, sizeof (senderAddr));
            senderAddr.sin_family       = AF_INET;
            senderAddr.sin_port         = htons (PORT_NUM);
            senderAddr.sin_addr.s_addr  = htonl (INADDR_ANY);

            addrLen = sizeof(senderAddr);

            while ((count = ReceiveFrom((void*)&message, mesgLen,
                  (SOCKADDR*) &senderAddr, &addrLen)) != 0)
            {
                  if ((count != SOCKET_ERROR) && (count == sizeof(NLDMessage))) {
                            // Process message and reply back to sender
                            WriteMsg(&outMsg, &senderAddr);
                  } else {
                        int errcode = 0;
                        errcode = GetLastError();
                  }
            }
                  
            if (count == 0) {
                        // Connection closed
                  return;
            }
      }
}

UINT ListenToLicense(LPVOID pParam);


class Manager
{
protected:
      CMySocket            mySocket;
public:
      Manager();
      Manager(CWnd* pParentWnd);
      virtual ~Manager();
      void Broadcast();
      void Detect();
};

void Manager::Broadcast() {
      Message      mesg;
      mySocket.BroadcastMsg(mesg);
}
void Manager::Detect() {
      AfxBeginThread(ListenTo, this);
}
void Manager::DetectMsg() {
      mySocket.DetectMsg();
}

UINT ListenToLicense(LPVOID pParam) {
    Manager* localNLD = (Manager*)pParam;
    localNLD->DetectMsg();      
    return (0);
}

And in the main CWinApp InitApplication, I do this:

      Manager mana(AfxGetMainWnd());

      mana.Broadcast();
      man.Detect();
      man.Broadcast();
0
 

Author Comment

by:hoooi
Comment Utility
Thank you all. Over the weekend, I've tried all kinda solutions. I tried:
AsyncSelect(0), IOCtl(FIONBIO, &value) value is 0, derive a class fr CWinThread following the example http://support.microsoft.com/support/kb/articles/Q175/6/68.ASP, and a lot more, and I always get different errors. Let me explain what I use socket for.
1) When I launch my app, I broadcast a message, I will need to receive response back, but I will worry about it later.
2) My app will then start a thread that listen to messages fr #1 fr other machines that do the same. Whenever a message fr #1 is received, process something, then reply back only to the machine that broadcasts.
3) The port number should remain the same everytime the app starts. I don't know if the broadcast or receive uses it though.

The reason I don't use OnReceive (I tried before) is because I simply don't know how it can be trigerred. When I broadcast, I should be able to receive the my own message, and I don't see it happen in OnReceive. I read that I will need GetMessage, TranslateMessage and DispatchMessage, and it only works if you have dialog/window, but I don't know how and it cannot involve dialog. The callback doesn't quite work for me. So, I'm trying to convert ReceiveFrom to blocking, but unsuccessful.

Here are my classes:

class CMySocket : public CAsyncSocket
{
protected:
      BOOL                  onLAN;
public:
      CMySocket ();
      virtual ~CMySocket ();
      void BroadcastMsg(Message inMsg);
      void WriteMsg(Message *outMsg, sockaddr_in* lpSockAddr);
      void DetectMsg();
      virtual void OnReceive(int nErrorCode);
};

#include <stdafx.h>
#include "CMySocket.h"

CMySocket::CMySocket () : CAsyncSocket() {
      BOOL      bInit;
      BOOL      bCreate;
      BOOL      bSetOpt;
      BOOL    bSe
      BOOL      broadcastValue = TRUE;
      
      onLAN = TRUE;

      bInit = AfxSocketInit(NULL);
      bCreate = Create(PORT_NUM, SOCK_DGRAM);
      bSetOpt = SetSockOpt(SO_BROADCAST, &broadcastValue, sizeof(BOOL));
      BOOL bSe = AsyncSelect(0);
}

CMySocket::~CMySocket() {}

void CMySocket::BroadcastMsg(Message outMsg) {
      BOOL retcode;
      // NULL == broadcast
      retcode = SendTo((void*)&outMsg, sizeof(NLDMessage), PORT_NUM, NULL, 0);

      if (retcode == SOCKET_ERROR) {
            int errcode = 0;
            errcode = GetLastError();
      }
}

void CMySocket::WriteMsg(Message *outMsg, sockaddr_in* lpSockAddr) {
      BOOL retcode;
      // This is used when replying to a specific machine
      retcode = SendTo((void*)outMsg, sizeof(NLDMessage), (SOCKADDR *)lpSockAddr, sizeof (lpSockAddr), 0);
}

void CMySocket::DetectMsg()
{
      DWORD value = 0;
      BOOL bIO = IOCtl(FIONBIO, &value);
      
      if (bIO == 0) {
            int errcode = 0;
            errcode = GetLastError();
      }

      if (onLAN == TRUE) {
            Message      message, outMsg;
            sockaddr_in senderAddr;
            int                  addrLen;
            int                  mesgLen;
            int                  count;

            memset (&message, 0, sizeof (Message));
            mesgLen = sizeof(Message);

            memset (&senderAddr, 0, sizeof (senderAddr));
            senderAddr.sin_family       = AF_INET;
            senderAddr.sin_port         = htons (PORT_NUM);
            senderAddr.sin_addr.s_addr  = htonl (INADDR_ANY);

            addrLen = sizeof(senderAddr);

            while ((count = ReceiveFrom((void*)&message, mesgLen,
                  (SOCKADDR*) &senderAddr, &addrLen)) != 0)
            {
                  if ((count != SOCKET_ERROR) && (count == sizeof(NLDMessage))) {
                            // Process message and reply back to sender
                            WriteMsg(&outMsg, &senderAddr);
                  } else {
                        int errcode = 0;
                        errcode = GetLastError();
                  }
            }
                  
            if (count == 0) {
                        // Connection closed
                  return;
            }
      }
}

UINT ListenToLicense(LPVOID pParam);


class Manager
{
protected:
      CMySocket            mySocket;
public:
      Manager();
      Manager(CWnd* pParentWnd);
      virtual ~Manager();
      void Broadcast();
      void Detect();
};

void Manager::Broadcast() {
      Message      mesg;
      mySocket.BroadcastMsg(mesg);
}
void Manager::Detect() {
      AfxBeginThread(ListenTo, this);
}
void Manager::DetectMsg() {
      mySocket.DetectMsg();
}

UINT ListenToLicense(LPVOID pParam) {
    Manager* localNLD = (Manager*)pParam;
    localNLD->DetectMsg();      
    return (0);
}

And in the main CWinApp InitApplication, I do this:

      Manager mana(AfxGetMainWnd());

      mana.Broadcast();
      man.Detect();
      man.Broadcast();
0
 
LVL 9

Expert Comment

by:ShaunWilde
Comment Utility
> I read that I will need GetMessage, TranslateMessage and DispatchMessage

what you need is a message pump this is supplied by the CWinThread derived objects eg CWinApp and your other threads which create which are derived from CWinThread

you should call AfxSocketInit in the InitInstance method of you CWinApp/CWinThread classes

what does you OnReceive handler look like?
0
 

Author Comment

by:hoooi
Comment Utility
My OnReceive looks just like DetectMsg, with CAsyncSocket::OnReceive(errorCode) at the bottom. I didn't put it here because it didn't work for me.
I wrote another 2 classes that have the following, I pretty much copied the codes fr a msdn article:
void CReceiver::OnAccept(int nErrorCode)
{
     CSocket soc;
     int          lpSockAddrLen;

     Accept(soc, &replyToAddr, &lpSockAddrLen );
     CReceiverThread* pThread = (CReceiverThread*)AfxBeginThread(
          RUNTIME_CLASS(CReceiverThread),
          THREAD_PRIORITY_NORMAL,
          0,
          CREATE_SUSPENDED);

     pThread->m_hSocket = soc.Detach();

     pThread->ResumeThread();

     CAsyncSocket::OnAccept(nErrorCode);
}

BOOL CReceiverThread::InitInstance()
{
     BOOL bAttach;

     bAttach = m_socket.Attach(m_hSocket);

     if (bAttach == 0)
     {
          int errcode = 0;
          errcode = GetLastError();
     }

     return (bAttach);
}
0
 
LVL 9

Expert Comment

by:ShaunWilde
Comment Utility
if you want to use OnReceive then let it get called once per message eg remove the while loop from DetectMsg - no guarantees - but I personally don't use read loops unless I am using stream sockets or readin in large packets but if I am dealing with datagrams I keep the data short and if I need to sned loarge blocks then I switch to a stream socket and then I always peek the buffer before hand to see if there is anything there

also if speed is important package up the socket details and message etc into an object and send it to another thread for processing and then notify the socket threrad that there is data to send - you might be able to use the OnSend handler I use a triggered OnSend Handler

commentcode

most of my packets have the following structure

| size | type | header |

virtual void OnReceive() // similar for both stream and dgram
{
  // is there ant data - since we have been called there should be something

  // peek the first few bytes and get the length data

  // do we have that in our buffer - keep polling till we do - or return and come back again

  // read in a packet with all socket info

  // package up into an object and add to list

  // trigger processing thread by either a postmessage of event depending on the thread type
 
 
}

virtual void MyOnSend() // triggered by a WM_MYONSENDMESSAGE
{
  // is there any data to process - no then return

  // take the first message from the list - protected by a critical section

  // send message

  // any more to send then send a WM_MYONSENDMESSAGE this gives the OnReceive a chance to butt in if necessary
}
0
 

Expert Comment

by:ahmadrazakhan
Comment Utility
this class was written for UDP messages. in constructor u pass an integer for port and an identifier for describing is this socket for sending data  or listening. this can create a socket which broadcast messages and these messages will b received on same machine also.



// UltraUdpSocket.cpp : implementation file
//

#include "stdafx.h"
#include "UltraUdpSocket.h"

#include "MessagingInterface.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CUdpAsySk

CUltraUDPSocket::CUltraUDPSocket(UINT nSocketType, UINT nPortNo)
{
      int sock;                         /* Socket */

      if (nSocketType == RECEIVER_SOCKET)
      {

            struct sockaddr_in broadcastAddr; /* Broadcast Address */
            unsigned int broadcastPort;       /* Port */
            unsigned long nonblocking = 1;    /* Flag to make socket nonblocking */

            broadcastPort = nPortNo;    /* second arg:  broadcast port */

            /* Create a best-effort datagram socket using UDP */
            if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
                  DieWithError();

            /* Set the socket to nonblocking */
            if (ioctlsocket(sock, FIONBIO, &nonblocking) != 0)
                  DieWithError();

            int broadcastPermission = 1;
            if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *) &broadcastPermission,
              sizeof(broadcastPermission)) < 0)
            DieWithError();

            /* Construct bind structure */
            memset(&broadcastAddr, 0, sizeof(broadcastAddr));   /* Zero out structure */
            broadcastAddr.sin_family = AF_INET;                 /* Internet address family */
            broadcastAddr.sin_addr.s_addr = htonl(INADDR_ANY);  /* Any incoming interface */
            broadcastAddr.sin_port = htons(broadcastPort);      /* Broadcast port */

            /* Bind to the broadcast port */
            if (bind(sock, (struct sockaddr *) &broadcastAddr, sizeof(broadcastAddr)) < 0)
                  DieWithError();

//            unsigned int wMsg = 55551;
//            WSAAsyncSelect (sock, AfxGetMainWnd()->m_hWnd,wMsg,  
//                                FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE);
      
            this->Attach(sock, FD_READ);      //give notification message only if data is available for reading
      }
      else
      {            //Create Sender socket
            char *broadcastIP;                /* IP broadcast address */
            unsigned short broadcastPort;     /* Server port */
            int broadcastPermission;          /* Socket opt to set permission to broadcast */

            broadcastIP = "255.255.255.255" ;          /* first arg:  broadcast IP address */
            broadcastPort = nPortNo;    /* second arg:  broadcast port */

            /* Create socket for sending/receiving datagrams */
            if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
                  DieWithError();

            /* Set socket to allow broadcast */
            broadcastPermission = 1;
            if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *) &broadcastPermission,
              sizeof(broadcastPermission)) < 0)
            DieWithError();

            if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const char *) &broadcastPermission,
                    sizeof(broadcastPermission)) < 0)
                  DieWithError();

            this->Attach(sock, 0);      //no notification messages are required
      }

      m_Port = nPortNo;
}

CUltraUDPSocket::~CUltraUDPSocket()
{
}

// Do not edit the following lines, which are needed by ClassWizard.
#if 0
BEGIN_MESSAGE_MAP(CUltraUDPSocket, CAsyncSocket)
      //{{AFX_MSG_MAP(CUltraUDPSocket)
      //}}AFX_MSG_MAP
END_MESSAGE_MAP()
#endif      // 0

/////////////////////////////////////////////////////////////////////////////
// CUltraUDPSocket member functions
void CUltraUDPSocket::OnReceive(int nErrorCode)
{
      TCHAR buff[70000];                                                            //70k
      int nRead;

      CString BroadcastIP = "255.255.255.255";                        //its a broadcat default IP
      nRead = ReceiveFrom(buff, 69999, BroadcastIP, m_Port);      //make it smaller so we can experiment mulitple notifications

      CString szMsg;
      switch (nRead)
      {
      case 0:
            szMsg.Format("**ErrorMsg**;UDP Error: No data reveived in function OnReceive in UltraUdpSocket class");
            break;

      case SOCKET_ERROR:
            if (GetLastError() == WSAEWOULDBLOCK)
            {
                  szMsg.Format("**ErrorMsg**;UDP Error: WSAEWOULDBLOCK (Resource temporarily unavailable) in OnReceive in UltraUdpSocket class");
            }
            else
            if (GetLastError() == WSAEMSGSIZE)
            {
                  szMsg.Format("**ErrorMsg**;UDP Error: The datagram was too large and was truncated; in function OnReceive in UltraUdpSocket class");
            }
            else
            {
                  szMsg.Format("**ErrorMsg**;UDP Error: in function OnReceive in UltraUdpSocket class; error code: %d", GetLastError());
            }
            break;

      default:      //ok; data received successfully
            if (nRead != SOCKET_ERROR && nRead != 0 )
            {
                  buff[nRead] = 0;            //terminate the string
                  szMsg = buff;
            }      

            //send msg to Interface, it will further send it to client
            ((CMessagingInterface*) m_pMessagingInterface)->OnUDPReceive(szMsg, NULL);
      }

      CAsyncSocket::OnReceive(nErrorCode);
}

void CUltraUDPSocket::DieWithError()
{
      CString temp;
      temp.Format("Failed to create UDP socket: %d! Close and restart app.", GetLastError());
      AfxMessageBox (temp);
}
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 

Expert Comment

by:ahmadrazakhan
Comment Utility
this class was written for UDP messages. in constructor u pass an integer for port and an identifier for describing is this socket for sending data  or listening. this can create a socket which broadcast messages and these messages will b received on same machine also.



// UltraUdpSocket.cpp : implementation file
//

#include "stdafx.h"
#include "UltraUdpSocket.h"

#include "MessagingInterface.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CUdpAsySk

CUltraUDPSocket::CUltraUDPSocket(UINT nSocketType, UINT nPortNo)
{
      int sock;                         /* Socket */

      if (nSocketType == RECEIVER_SOCKET)
      {

            struct sockaddr_in broadcastAddr; /* Broadcast Address */
            unsigned int broadcastPort;       /* Port */
            unsigned long nonblocking = 1;    /* Flag to make socket nonblocking */

            broadcastPort = nPortNo;    /* second arg:  broadcast port */

            /* Create a best-effort datagram socket using UDP */
            if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
                  DieWithError();

            /* Set the socket to nonblocking */
            if (ioctlsocket(sock, FIONBIO, &nonblocking) != 0)
                  DieWithError();

            int broadcastPermission = 1;
            if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *) &broadcastPermission,
              sizeof(broadcastPermission)) < 0)
            DieWithError();

            /* Construct bind structure */
            memset(&broadcastAddr, 0, sizeof(broadcastAddr));   /* Zero out structure */
            broadcastAddr.sin_family = AF_INET;                 /* Internet address family */
            broadcastAddr.sin_addr.s_addr = htonl(INADDR_ANY);  /* Any incoming interface */
            broadcastAddr.sin_port = htons(broadcastPort);      /* Broadcast port */

            /* Bind to the broadcast port */
            if (bind(sock, (struct sockaddr *) &broadcastAddr, sizeof(broadcastAddr)) < 0)
                  DieWithError();

//            unsigned int wMsg = 55551;
//            WSAAsyncSelect (sock, AfxGetMainWnd()->m_hWnd,wMsg,  
//                                FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE);
      
            this->Attach(sock, FD_READ);      //give notification message only if data is available for reading
      }
      else
      {            //Create Sender socket
            char *broadcastIP;                /* IP broadcast address */
            unsigned short broadcastPort;     /* Server port */
            int broadcastPermission;          /* Socket opt to set permission to broadcast */

            broadcastIP = "255.255.255.255" ;          /* first arg:  broadcast IP address */
            broadcastPort = nPortNo;    /* second arg:  broadcast port */

            /* Create socket for sending/receiving datagrams */
            if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
                  DieWithError();

            /* Set socket to allow broadcast */
            broadcastPermission = 1;
            if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *) &broadcastPermission,
              sizeof(broadcastPermission)) < 0)
            DieWithError();

            if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const char *) &broadcastPermission,
                    sizeof(broadcastPermission)) < 0)
                  DieWithError();

            this->Attach(sock, 0);      //no notification messages are required
      }

      m_Port = nPortNo;
}

CUltraUDPSocket::~CUltraUDPSocket()
{
}

// Do not edit the following lines, which are needed by ClassWizard.
#if 0
BEGIN_MESSAGE_MAP(CUltraUDPSocket, CAsyncSocket)
      //{{AFX_MSG_MAP(CUltraUDPSocket)
      //}}AFX_MSG_MAP
END_MESSAGE_MAP()
#endif      // 0

/////////////////////////////////////////////////////////////////////////////
// CUltraUDPSocket member functions
void CUltraUDPSocket::OnReceive(int nErrorCode)
{
      TCHAR buff[70000];                                                            //70k
      int nRead;

      CString BroadcastIP = "255.255.255.255";                        //its a broadcat default IP
      nRead = ReceiveFrom(buff, 69999, BroadcastIP, m_Port);      //make it smaller so we can experiment mulitple notifications

      CString szMsg;
      switch (nRead)
      {
      case 0:
            szMsg.Format("**ErrorMsg**;UDP Error: No data reveived in function OnReceive in UltraUdpSocket class");
            break;

      case SOCKET_ERROR:
            if (GetLastError() == WSAEWOULDBLOCK)
            {
                  szMsg.Format("**ErrorMsg**;UDP Error: WSAEWOULDBLOCK (Resource temporarily unavailable) in OnReceive in UltraUdpSocket class");
            }
            else
            if (GetLastError() == WSAEMSGSIZE)
            {
                  szMsg.Format("**ErrorMsg**;UDP Error: The datagram was too large and was truncated; in function OnReceive in UltraUdpSocket class");
            }
            else
            {
                  szMsg.Format("**ErrorMsg**;UDP Error: in function OnReceive in UltraUdpSocket class; error code: %d", GetLastError());
            }
            break;

      default:      //ok; data received successfully
            if (nRead != SOCKET_ERROR && nRead != 0 )
            {
                  buff[nRead] = 0;            //terminate the string
                  szMsg = buff;
            }      

            //send msg to Interface, it will further send it to client
            ((CMessagingInterface*) m_pMessagingInterface)->OnUDPReceive(szMsg, NULL);
      }

      CAsyncSocket::OnReceive(nErrorCode);
}

void CUltraUDPSocket::DieWithError()
{
      CString temp;
      temp.Format("Failed to create UDP socket: %d! Close and restart app.", GetLastError());
      AfxMessageBox (temp);
}
0
 

Author Comment

by:hoooi
Comment Utility
Hi ahmadrazakhan , your code makes perfect sense to me. I'm sure it's getting close now. Can you provide the UltraUdpSocket.h file as well? I am a novice, just started learning mfc, so I got a few more questions.
1. Does it work in console program only? Cause I have to plug the code into a CWinApp, so I assume the OnReceive is somehow trigerred. And I assume it has to do with message map?
2. Where is the broadcast message part? Is it this part
          //send msg to Interface, it will further send it to client
          ((CMessagingInterface*) m_pMessagingInterface)->OnUDPReceive(szMsg, NULL);
If so, I don't quite understand... can you please explain a little more?

Thanks so much!



Thanks much.
0
 

Accepted Solution

by:
ahmadrazakhan earned 100 total points
Comment Utility
1)UltraUdpSocket class encapsulates UDP broadcast only.
2)u can create its object in 2 ways either CUltraUDPSocket   (SENDER_SOCKET, 4444) or CUltraUDPSocket(RECEIVER_SOCKET, 4444), Object created with SENDER_SOCKET is used for sending broadcasts on port 4444, the other will listen broadcast on port 4444. u will define urself constants SENDER_SOCKET and RECEIVER_SOCKET.

whenever data arrives i collect it and pass it to another class CMessagingInterface for processing.
i use another class for sending data, this code will not let u send data, u will b only able to listen broadcasts,

similarly i have one more class which encapsulates TCP communcation. if u needed give me ur email, i will send u complete code listing.

here is header


#if !defined(AFX_UltraUdpSocket_H__20F99C82_8C83_11D1_A121_0000F875C45F__INCLUDED_)
#define AFX_UltraUdpSocket_H__20F99C82_8C83_11D1_A121_0000F875C45F__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
// UltraUdpSocket.h : header file
//
#include "AfxSock.h"

#define      SENDER_SOCKET      0
#define  RECEIVER_SOCKET 1
/////////////////////////////////////////////////////////////////////////////
// CUltraUDPSocket command target

class CUltraUDPSocket : public CAsyncSocket
{
// Attributes
public:
     void     *m_pMessagingInterface;
     UINT     m_Port;

// Operations
public:
     CUltraUDPSocket(UINT nSocketType, UINT nPortNo);
     virtual ~CUltraUDPSocket();
     void     DieWithError();
// Overrides
public:
     // ClassWizard generated virtual function overrides
     //{{AFX_VIRTUAL(CUltraUDPSocket)
     public:
     virtual void OnReceive(int nErrorCode);
     //}}AFX_VIRTUAL

     // Generated message map functions
     //{{AFX_MSG(CUltraUDPSocket)
          // NOTE - the ClassWizard will add and remove member functions here.
     //}}AFX_MSG

// Implementation
protected:
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_UltraUdpSocket_H__20F99C82_8C83_11D1_A121_0000F875C45F__INCLUDED_)

0
 

Author Comment

by:hoooi
Comment Utility
I will try the codes as soon as I can, thanks!
0
 

Author Comment

by:hoooi
Comment Utility
Hi, the OnReceive is never get called in my code. I'm able to broadcast messages. The way I use it is I declare the CUltraUDPSocket to receive and that's all I do. I don't think the declaration can trigerred OnReceive... what else should I do? Thanks.
0
 

Expert Comment

by:ahmadrazakhan
Comment Utility
do these steps, it will work
1)make dialog based application, with sockets support(it will write AfxSocketInit() for u)
2)Add this to Dlg.h file

#include "UltraUDPSocket.h"

CUltraUDPSocket *m_pSenderUDPSocket, *m_pReceiverUDPSocket;

3)Add this to dlg.cpp

say in OnOk()



#define      SENDER_SOCKET      0
#define  RECEIVER_SOCKET 1

void CDlgDlg::OnOk()
{

     if ((m_pSenderUDPSocket = new CUltraUDPSocket(SENDER_SOCKET, 555)) == NULL)
     {
          AfxMessageBox ("Failed to allocate UDP socket! Close and restart application.");
     }
     if ((m_pReceiverUDPSocket = new CUltraUDPSocket(RECEIVER_SOCKET, 555)) == NULL)
     {
          AfxMessageBox ("Failed to allocate UDP socket! Close and restart application.");
     }

     SOCKADDR_IN remoteAddr;
     remoteAddr.sin_family = AF_INET;
     remoteAddr.sin_port = htons(m_pSenderUDPSocket->m_Port);
     remoteAddr.sin_addr.s_addr = htonl(INADDR_BROADCAST);     //INADDR_BROADCAST = "255.255.255.255"

     int BytesSent = m_pSenderUDPSocket->SendTo("HelloWorld", 10, (const SOCKADDR* )&remoteAddr, sizeof(remoteAddr));      //send function may send less than the total bytes

}



Press Ok button it will send data, and quickly Onreceive in socket class will be called
0
 
LVL 9

Expert Comment

by:ShaunWilde
Comment Utility
> Hi, the OnReceive is never get called in my code

I've mentioned this before but do you have a message pump in your app what type of app is it?
0
 

Expert Comment

by:ahmadrazakhan
Comment Utility
do these steps, it will work
1)make dialog based application, with sockets support(it will write AfxSocketInit() for u)
2)Add this to Dlg.h file

#include "UltraUDPSocket.h"

CUltraUDPSocket *m_pSenderUDPSocket, *m_pReceiverUDPSocket;

3)Add this to dlg.cpp

say in OnOk()



#define      SENDER_SOCKET      0
#define  RECEIVER_SOCKET 1

void CDlgDlg::OnOk()
{

     if ((m_pSenderUDPSocket = new CUltraUDPSocket(SENDER_SOCKET, 555)) == NULL)
     {
          AfxMessageBox ("Failed to allocate UDP socket! Close and restart application.");
     }
     if ((m_pReceiverUDPSocket = new CUltraUDPSocket(RECEIVER_SOCKET, 555)) == NULL)
     {
          AfxMessageBox ("Failed to allocate UDP socket! Close and restart application.");
     }

     SOCKADDR_IN remoteAddr;
     remoteAddr.sin_family = AF_INET;
     remoteAddr.sin_port = htons(m_pSenderUDPSocket->m_Port);
     remoteAddr.sin_addr.s_addr = htonl(INADDR_BROADCAST);     //INADDR_BROADCAST = "255.255.255.255"

     int BytesSent = m_pSenderUDPSocket->SendTo("HelloWorld", 10, (const SOCKADDR* )&remoteAddr, sizeof(remoteAddr));      //send function may send less than the total bytes

}



Press Ok button it will send data, and quickly Onreceive in socket class will be called
0
 

Expert Comment

by:ahmadrazakhan
Comment Utility
do these steps, it will work
1)make dialog based application, with sockets support(it will write AfxSocketInit() for u)
2)Add this to Dlg.h file

#include "UltraUDPSocket.h"

CUltraUDPSocket *m_pSenderUDPSocket, *m_pReceiverUDPSocket;

3)Add this to dlg.cpp

say in OnOk()



#define      SENDER_SOCKET      0
#define  RECEIVER_SOCKET 1

void CDlgDlg::OnOk()
{

     if ((m_pSenderUDPSocket = new CUltraUDPSocket(SENDER_SOCKET, 555)) == NULL)
     {
          AfxMessageBox ("Failed to allocate UDP socket! Close and restart application.");
     }
     if ((m_pReceiverUDPSocket = new CUltraUDPSocket(RECEIVER_SOCKET, 555)) == NULL)
     {
          AfxMessageBox ("Failed to allocate UDP socket! Close and restart application.");
     }

     SOCKADDR_IN remoteAddr;
     remoteAddr.sin_family = AF_INET;
     remoteAddr.sin_port = htons(m_pSenderUDPSocket->m_Port);
     remoteAddr.sin_addr.s_addr = htonl(INADDR_BROADCAST);     //INADDR_BROADCAST = "255.255.255.255"

     int BytesSent = m_pSenderUDPSocket->SendTo("HelloWorld", 10, (const SOCKADDR* )&remoteAddr, sizeof(remoteAddr));      //send function may send less than the total bytes

}



Press Ok button it will send data, and quickly Onreceive in socket class will be called
0
 

Author Comment

by:hoooi
Comment Utility
Okay I just called AfxSocketInit() in my InitInstance, and the OnReceived is receiving now (great!) but it keeps receiving non-stop eventhough I only broadcast once...
0
 

Author Comment

by:hoooi
Comment Utility
Sorry, let me rephrase, I broadcast once, I received twice. Is this normal?
0
 

Expert Comment

by:ahmadrazakhan
Comment Utility
No, it should not behave like this, i hope if u follow my above steps u will C correct beavior
0
 
LVL 9

Expert Comment

by:ShaunWilde
Comment Utility
> Okay I just called AfxSocketInit() in my InitInstance

did you not read my earlier post ?
0
 

Author Comment

by:hoooi
Comment Utility
I run the same app on win NT and the OnReceived gets called once somehow. That good enough, I'll figure out the rest. Thanks for your time.
0

Featured Post

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

In this article, I'll describe -- and show pictures of -- some of the significant additions that have been made available to programmers in the MFC Feature Pack for Visual C++ 2008.  These same feature are in the MFC libraries that come with Visual …
Introduction: Dialogs (2) modeless dialog and a worker thread.  Handling data shared between threads.  Recursive functions. Continuing from the tenth article about sudoku.   Last article we worked with a modal dialog to help maintain informat…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now