CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 8 of 8
  1. #1
    Join Date
    Sep 2004
    Location
    New Delhi, India
    Posts
    640

    Question Asynchronous sockets?

    I have a question regarding asynchronous sockets. I have a server and client application. The client selects a file and that file should be transmitted to the server. The client connects to the server starts reading the file and transmits its contents, the problem is how on the server side do I collect them? What I mean is that in case of asynchronus sockets the server is notified only when there is data to be recieved, in such a case recv () is thus non blocking, then how do i determine from where is the data coming? And how do I collect it?

    On the server side I start a thread everytime a client connects but the recv () being non blocking immediately goes out and the thread ends. I tried something like this:
    Code:
    //The message handler which is called each time there is data to be recieved
    HRESULT CASyncServerDlg::OnSocket (WPARAM wParam, LPARAM lParam)
    {
    	sockaddr_in from;
    	int len = sizeof (from);
    	SOCKET client;
    	TCHAR buffer [MAX_PATH];
    	if (LOWORD (lParam) == FD_ACCEPT)
    	{
    		client= accept (server,
    			(struct sockaddr*)&from, &len);
    		sprintf (buffer, "Message from server! You are connected!");
    		send (client, buffer, _tcslen (buffer), 0);
    		AfxBeginThread (ClientThread, (LPVOID)client);
    	}
    /*
    	if (LOWORD (lParam) == FD_READ)
    	{
    		int nRet = recv ((SOCKET)wParam, buffer, MAX_PATH, 0);
    		buffer [nRet] = 0;
    		m_ListBox.AddString (buffer);
    	}
    */
    	return 0;
    }
    
    //The thread function
    UINT CASyncServerDlg::ClientThread (LPVOID pParam)
    {
    	SOCKET client = (SOCKET)pParam;
    	TCHAR buffer [MAX_PATH];
    	CFile file;
    	file.Open ("C:\\file.dat", CFile::modeWrite | CFile::modeCreate);
    	int nRet = recv (client, buffer, MAX_PATH, 0);
    	do
    	{
    		file.Write (reinterpret_cast<void *>(buffer), MAX_PATH);
    		nRet = recv (client, buffer, MAX_PATH, 0);
    	}
    	while (nRet > 0);
    	file.Close ();
    	return 0;
    }
    Iam quite perplexed, looking for some directions now...

    Regards.
    "I rather not play football than wear Nerrazzuri shirt" - Paolo Maldini
    FORZA MILAN!!!

  2. #2
    Join Date
    Nov 2002
    Location
    California
    Posts
    4,556

    Re: Asynchronous sockets?

    You have a few issues with this code.

    First, in the main thread, when a socket is accepted, it inherits the charactersitics of the listening socket. In your case, the listening socket is non-blocking, but since you want your clients to be hanfdled synchronously in a separate thread, you need them to be changed to blocking sockets. You can change the accepted socket to blocking with ioctlsocket, but you first need to call WSAAsyncSelect with NULL for the notifications, as described in the documentation.

    Again in the main thread, your accepted SOCKET is a stack object that will go out-of-scope as soon as the OnAccept() function returns. Thus, the thread will not assuredly get a valid socket handle (although it might get a valid handle simply by chance, depending on how the compiler handles memory).

    On the thread side, your "successful connection" method should probably be moved to the thread since it's now a blocking send that might stall the main thread.

    The file.Write operations should not write MAX_PATH number of bytes, since this is not necessarily the amount of bytes that the recv() will give you. You should write nRet number of bytes instead.

    Here's a quick idea of what I mean by the above:

    Code:
    //The message handler which is called each time there is data to be recieved
    HRESULT CASyncServerDlg::OnSocket (WPARAM wParam, LPARAM lParam)
    {
      sockaddr_in from;
      int len = sizeof (from);
      //// SOCKET client;
      TCHAR buffer [MAX_PATH];
      if (LOWORD (lParam) == FD_ACCEPT)
      {
        SOCKET* pClient = new SOCKET;
        *pClient= accept (server,
          (struct sockaddr*)&from, &len);
        WSAAsyncSelect( *pClient, hMainWnd, 0, 0 );
        ulong blocking = 0;
        ioctlsocket( *pClient, FIONBIO, &blocking );    
    ////    sprintf (buffer, "Message from server! You are connected!");
    ////    send (client, buffer, _tcslen (buffer), 0);
        AfxBeginThread (ClientThread, (LPVOID)pClient);
      }
    /*
    /// you are correct that this code is not needed
      if (LOWORD (lParam) == FD_READ)
      {
        int nRet = recv ((SOCKET)wParam, buffer, MAX_PATH, 0);
        buffer [nRet] = 0;
        m_ListBox.AddString (buffer);
      }
    */
      
      return 0;
    }
    
    //The thread function
    UINT CASyncServerDlg::ClientThread (LPVOID pParam)
    {
      SOCKET client = *((SOCKET*)pParam);
      TCHAR buffer [MAX_PATH];
      sprintf (buffer, "Message from server! You are connected!");
      send (client, buffer, _tcslen (buffer), 0);
      CFile file;
      file.Open ("C:\\file.dat", CFile::modeWrite | CFile::modeCreate);
      int nRet = recv (client, buffer, MAX_PATH, 0);
      do
      {
        file.Write (reinterpret_cast<void *>(buffer), nRet  );
        nRet = recv (client, buffer, MAX_PATH, 0);
      }
      while (nRet > 0);
      file.Close ();
      delete &client;
      return 0;
    }
    You also need a lot of error checking (your code now has none).

    Mike

  3. #3
    Join Date
    Sep 2004
    Location
    New Delhi, India
    Posts
    640

    Re: Asynchronous sockets?

    Thank you very much. It was very helpful.
    Quote Originally Posted by MikeAThon
    since you want your clients to be hanfdled synchronously in a separate thread
    Is there a way by which I can achieve the above scenariao via asynchronous sockets?

    Regards.
    "I rather not play football than wear Nerrazzuri shirt" - Paolo Maldini
    FORZA MILAN!!!

  4. #4
    Join Date
    Jul 2005
    Location
    Germany
    Posts
    1,194

    Re: Asynchronous sockets?

    Quote Originally Posted by logan
    Is there a way by which I can achieve the above scenariao via asynchronous sockets?
    You can use WSAEventSelect(). This is the initialization:
    Code:
    DWORD dwThreadID;
    WSAEVENT event = WSACreateEvent();
    WSAEventSelect(socket, event, FD_READ | FD_CLOSE);
    HANDLE hThread = CreateThread(NULL, 0, &EventThread, (LPVOID)event, 0, &dwThreadID);
    CloseHandle(hThread);
    This is the event thread:
    Code:
    DWORD WINAPI EventThread(LPVOID lpParameter)
    {
      WSAEVENT hNetEvent = (WSAEVENT)lpParameter;
      while(true)
      {
        WSANETWORKEVENTS dNetworkEvents;
    
        WSAWaitForMultipleEvents(1, &hNetEvent, FALSE, WSA_INFINITE, FALSE);
        WSAEnumNetworkEvents(socket, hNetEvent, &dNetworkEvents);
        if(dNetworkEvents.lNetworkEvents == FD_READ)
          OnReceive();
        else if(dNetworkEvents.lNetworkEvents == FD_CLOSE)
        {
          OnClose();
          break;
        }
      }
      return 0;
    }
    Last edited by philkr; March 5th, 2006 at 03:22 PM.
    Please don't forget to rate users who helped you!

  5. #5
    Join Date
    Nov 2002
    Location
    California
    Posts
    4,556

    Re: Asynchronous sockets?

    Quote Originally Posted by logan
    ..Is there a way by which I can achieve the above scenariao via asynchronous sockets?
    Besides using event-based sockets (i.e., using WSAEventSelect in a separate thread), you can use ordinary message-based sockets (i.e., WSAAsyncSelect) in your main thread without using a worker thread.

    Use this architecture only if you do not expect too many simultaneous connections to your server. It's the second-least scalable solution for a server. However, for around less than 100 simultaneous connections tot he server, it's probably fine.

    Look at the CHATSRVR example in the FAQ: "Where can I find examples of socket programs?" at http://www.codeguru.com/forum/showthread.php?t=326666

    Mike

  6. #6
    Join Date
    Nov 2002
    Location
    California
    Posts
    4,556

    Re: Asynchronous sockets?

    Quote Originally Posted by philkr
    You can use WSAEventSelect(). This is the initialization:
    Code:
    DWORD dwThreadID;
    WSAEVENT event = WSACreateEvent();
    WSAEventSelect(socket, event, FD_READ | FD_CLOSE);
    HANDLE hThread = CreateThread(NULL, 0, &EventThread, (LPVOID)event, 0, &dwThreadID);
    CloseHandle(hThread);
    This is the event thread:
    Code:
    DWORD WINAPI EventThread(LPVOID lpParameter)
    {
      WSAEVENT hNetEvent = (WSAEVENT)lpParameter;
      while(true)
      {
        WSANETWORKEVENTS dNetworkEvents;
    
        WSAWaitForMultipleEvents(1, &hNetEvent, FALSE, WSA_INFINITE, FALSE);
        WSAEnumNetworkEvents(socket, hNetEvent, &dNetworkEvents);
        if(dNetworkEvents.lNetworkEvents == FD_READ)
          OnReceive();
        else if(dNetworkEvents.lNetworkEvents == FD_CLOSE)
        {
          OnClose();
          break;
        }
      }
      return 0;
    }
    It's possible for more than one network event to be signalled at one time, i.e., WSAEnumNetworkEvents will return a WSANETWORKEVENTS structure with more than one event signalled.

    So, do not check it with a "if -else if" logic, since that would detect only the first of possibly several network events. Use a sequence of plain "if" statments:

    Code:
    WSAWaitForMultipleEvents(1, &hNetEvent, FALSE, WSA_INFINITE, FALSE);
    WSAEnumNetworkEvents(socket, hNetEvent, &dNetworkEvents);
    
    if( (dNetworkEvents.lNetworkEvents & FD_READ  )== FD_READ)
    {
      OnReceive();
    }
    
    //// else  <--- delete this
    if ( (dNetworkEvents.lNetworkEvents & FD_CLOSE  )== FD_CLOSE)
    {
      OnClose();
    }
    
    if ( (dNetworkEvents.lNetworkEvents & FD_WRITE ) == FD_WRITE)
    {
      OnSend();
    }
    
    //// etc.
    Mike
    Last edited by MikeAThon; March 5th, 2006 at 05:46 PM. Reason: to change logical ANDs to binary ANDs -- sorry about that

  7. #7
    Join Date
    Jul 2005
    Location
    Germany
    Posts
    1,194

    Re: Asynchronous sockets?

    Thanks for the correction, Mike!
    Please don't forget to rate users who helped you!

  8. #8
    Join Date
    Sep 2004
    Location
    New Delhi, India
    Posts
    640

    Thumbs up Re: Asynchronous sockets?

    Thanks a lot guys. I will get back as the need be.

    Regards.
    "I rather not play football than wear Nerrazzuri shirt" - Paolo Maldini
    FORZA MILAN!!!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured