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
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.
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;
}
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
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
Re: Asynchronous sockets?
Thanks for the correction, Mike!
Re: Asynchronous sockets?
Thanks a lot guys. I will get back as the need be.
Regards.