?
Solved

CAsyncSocket

Posted on 2001-07-22
27
Medium Priority
?
2,517 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 9
  • 9
  • 7
  • +2
27 Comments
 
LVL 32

Expert Comment

by:jhance
ID: 6306014
CAsyncSockets are, by nature, non-blocking.  

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

Expert Comment

by:DanRollins
ID: 6306430
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
ID: 6307443
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
Learn how to optimize MySQL for your business need

With the increasing importance of apps & networks in both business & personal interconnections, perfor. has become one of the key metrics of successful communication. This ebook is a hands-on business-case-driven guide to understanding MySQL query parameter tuning & database perf

 

Expert Comment

by:ahmadrazakhan
ID: 6307741
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
ID: 6307921
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
ID: 6308056
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
ID: 6308301
> 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
ID: 6309311
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
ID: 6309312
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
ID: 6309644
> 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
ID: 6309954
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
ID: 6310139
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
ID: 6311088
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
 

Expert Comment

by:ahmadrazakhan
ID: 6311169
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
ID: 6311299
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 400 total points
ID: 6311912
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
ID: 6313193
I will try the codes as soon as I can, thanks!
0
 

Author Comment

by:hoooi
ID: 6321052
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
ID: 6321208
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
ID: 6321342
> 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
ID: 6321382
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
ID: 6321384
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
ID: 6325306
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
ID: 6325314
Sorry, let me rephrase, I broadcast once, I received twice. Is this normal?
0
 

Expert Comment

by:ahmadrazakhan
ID: 6325660
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
ID: 6326018
> Okay I just called AfxSocketInit() in my InitInstance

did you not read my earlier post ?
0
 

Author Comment

by:hoooi
ID: 6328385
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

Get MongoDB database support online, now!

At Percona’s web store you can order your MongoDB database support needs in minutes. No hassles, no fuss, just pick and click. Pay online with a credit card. Handle your MongoDB database support now!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction: Dynamic window placements and drawing on a form, simple usage of windows registry as a storage place for information. Continuing from the first article about sudoku.  There we have designed the application and put a lot of user int…
Introduction: The undo support, implementing a stack. Continuing from the eigth article about sudoku.   We need a mechanism to keep track of the digits entered so as to implement an undo mechanism.  This should be a ‘Last In First Out’ collec…
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.
In this brief tutorial Pawel from AdRem Software explains how you can quickly find out which services are running on your network, or what are the IP addresses of servers responsible for each service. Software used is freeware NetCrunch Tools (https…
Suggested Courses
Course of the Month13 days, 23 hours left to enroll

801 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