Introduction
Well, first off let me say this is my first article that I am posting here so please
forgive any terrible errors that I make. I scanned over many of the articles in the networking
section of the Code Project and couldn't find any that were relevant
to using Winsock2 Network Events.
Unfortunately this came at a time when I was looking to implement some
functionality in my program that used them.
That being the case, I bit the bullet and cracked open
the books. (Along with faithful MSDN of course.)
My Assumptions
There are some assumptions that I am making about the readers of this article. They are:
- Familiar with MFC 4.2 and VC. (These are obviously a must)
- Understand the difference between synchronous and asynchronous
- A basic understanding of socket programming. Nothing extremely heavy is required but
you should already know how to set up a socket and about the different
states it can be in, etc...
Why Network Events?
When I first examined the problem I was faced with, I had three different options to use.
The first was to use regular socket calls under
Winsock 1.1.�� The next approach I came across, which I might add only lasted as
long as it took me to read it, was to use notification of network "events"
through windows messages. This poised a very big problem considering the program I was
integrating this code into had no message pump. This brings us to the
solution: Notification through WSA Events.
How do they Work?
The idea is that there are a limited number of things that most people do
on a certain socket. You send data, receive data, connect to another
socket, accept incoming connect requests and you close a socket. There
are perhaps a couple more but we will only focus on the major ones
for this article.� When one of these things occurs, an event you associated
with it will signal and you do what ever is necessary. The
network events that can be handled are as follows (again, these are only the
ones we are going to be discussing):
-
FD_ACCEPT
-
FD_READ
-
FD_WRITE
-
FD_CLOSE
-
FD_CONNECT
Lets set up a small sample to demonstrate.�The first thing you need
to do is initialize the winsock2 library. There is probably more than one way to do this
but here is how I go about it.
WSADATA wsd;
LPFN_WSASTARTUP lpf =
(LPFN_WSA_STARTUP)::GetProcAddress(
::LoadLibrary("WS2_32.DLL"), "WSAStartup");
lpf(0x0202, &wsd);
The initialization can be done anywhere, as far as I know, provided
that it is done before you use any calls to
winsock functions. The next important thing to do is to create the event
we want to use to determine when one of network
events takes place. To do this, use the Winsock2 API call
to ::WSACreateEvent(); After the event is created
it must be associated with the socket that the events will
occur on and which events it is to handle. That will be done
with WSAEventSelect(...). For the following we
are setting up an event to signal on the arrival of a request
to connect. This is usually done on a listening socket.�
For us, this socket is SOCKET m_listen .
It will look like this:�
WSAEVENT hEvent = WSA_INVALID_EVENT;
hEvent = WSACreateEvent();
::WSAEventSelect(m_listen, hEvent, FD_ACCEPT);
If the socket in question was our data transfer socket,
say for example, SOCKET m_socket, that it would more
likely
look like this:
WSAEVENT hDataEvent = WSA_INVALID_EVENT;
hDataEvent = WSACreateEvent();
::WSAEventSelect(m_socket, hDataEvent, FD_WRITE | FD_READ | FD_CLOSE);
It should be noted that it is not possible to use two
different event objects to listen for different network events
on the same socket. You cannot do the following: �
WSAEVENT hEvent1 = WSA_INVALID_EVENT;
WSAEVENT hEvent2 = WSA_INVALID_EVENT;
hEvent1 = WSACreateEvent();
hEvent2 = WSACreateEvent();
::WSAEventSelect(m_socket, hEvent1, FD_READ);
::WSAEventSelect(m_socket, hEvent2, FD_WRITE);
Handling the Event Notifications
Now that the events we are going to use are set up,
we need a way of waiting on and handling them. The events are actually just regular
Win32 events which makes them a HANDLE.
The function we can use to wait for these events to occur
is WSAWaitForMultipleEvents(...). This
function will just cause the thread it is in to sleep
until a network event that we are handling
occurs. An example of this would be:
WSAEVENT hEvent1 = WSACreateEvent();
WSAEVENT hEvent2 = WSACreateEvent();
::WSAEventSelect(m_listen, hEvent1, FD_ACCEPT);
::WSAEventSelect(m_data, hEvent2, FD_READ | FD_CLOSE);
WSAEVENT* pEvents = (WSAEVENT*)::calloc(2, WSAEVENT);
pEvents[0] = hEvent1;
pEvents[1] = hEvent2;
int nReturnCode = ::WSAWaitForMultipleEvents(2, pEvents,
FALSE, INFINITE, FALSE);
If waiting for only one event the same function can be used.
Just alter it to look something like:
int nReturnCode = ::WSAWaitForMultipleEvents(1, &hEvent1,
FALSE, INFINITE, FALSE);
The first parameter is the number of events that you want to wait on.
The second is a pointer to an array of the events you want to
wait on. The third event is a
BOOL value that determines whether or not the wait
function should continue to sleep until all events have signaled.
This usually will be
false but you may find some need to wait on all events.
The fourth parameter is how long you want to wait. Since I usually put
this functionality in another thread I leave it at infinite. If
you have this in your main thread, you may want to limit it to 5 seconds
or some other timeout that relates to your application. The fourth
parameter is whether or not you want it to be
alertable. Now once an event fires there should be something that handles each event.
The first thing that needs to be done is to figure out exactly which
event fired. For this we can use the function
::WSAEnumNetworkEvents(...).
One of the parameters for this function is a structure
called WSANETWORKEVENTS . Moving along with the code
we had above, we would proceed to do the following:
WSANETWORKEVENTS hConnectEvent;
WSANETWORKEVENTS hProcessEvent;
::WSAEnumNetworkEvents(m_listen, hConnectEvent, &wsaConnectEvents);
::WSAEnumNetworkEvents(m_data, hProcessEvent, &wsaProcessEvents);
After that has been completed you have the event that
fired on one of the sockets. Now we need to break it down
and handle it per event so that the correct action is taken
for the correct event. This is done as follows:
if(
(wsaConnectEvents.lNetworkEvents & FD_ACCEPT) &&
(wsaConnectEvents.iErrorCode[FD_ACCEPT_BIT] == 0) )
{
}
This manner of checking can be done for each WSAEVENT you
have set up and for each network event that the
WSAEVENT will signal for. All that you must do it to change the
FD_ACCEPT to whatever network event you are handling and
change the error check bit to the appropriate variable.
Conclusion
I hope this helps somebody writing network applications.
I have tried to compact a lot of information into a small article
so I know that it may not answer all questions. Feel free to email me
or post questions below and I will try to answer all that I can.
I would also like to apologize for not having some sort of demo app
to go along with this article but I am very busy right now and all
the source that I currently have that uses network events is owned by my company.
| You must Sign In to use this message board. |
|
|
 |
|
 |
Hi, will you plz guide me how can i get network availability notification for any NIC in my application from windows. Thank you in advance.
|
| Sign In·View Thread·PermaLink | 1.38/5 |
|
|
|
 |
|
 |
Due to the age of this code and my inability to keep up with my long list of projects i am discontinuing any support for this article and/or support for the code that goes with it. Everything will remain as is here and you are still welcome to use it but please to not send me emails requesting updates, conversions, etc...
Best Regards,
Joseph Dempsey joseph_r_dempsey@yahoo.com
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
 |
hi i had wrote the code to initalize as below WSADATA wsd; LPFN_WSASTARTUP lpf = (LPFN_WSA_STARTUP)::GetProcAddress( ::LoadLibrary("WS2_32.DLL"), "WSAStartup"); lpf(0x0202, &wsd);
it gives the error that unknow symbol LPFN_WSASTARTUP so i read the question and of ur article. there u mentioned that include these #ifndef INCL_WINSOCK_API_TYPEDEFS //line 1 #define INCL_WINSOCK_API_TYPEDEFS 1 //line 2
it gives error that E:\VC21Days\Server\ServerDlg.cpp(268) : fatal error C1004: unexpected end of file found and this error is called due to the line1 tell me what to do.
ddd
|
| Sign In·View Thread·PermaLink | 2.00/5 |
|
|
|
 |
|
 |
I'm trying to use regular windows events with WSAEventSelect, but I'm running into some problems I'm not able to explain. (Which of course could just be me... The MSDN documentation for WSACreateEvent seems to imply that this is ok. Does this cause any problems that anybody knows of?
Thanks
|
| Sign In·View Thread·PermaLink | 1.00/5 |
|
|
|
 |
|
 |
Well i am figuring if it is possible to monitor incoming and outcoming packet of the APP using Netword Events rather than monitoring the RAS connection incoming and output bandwidth.
Cheers
Programming is not an end in itself but only a means to an end
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
"Since I usually put this functionality in another thread I leave it at infinite. "
I didn't know if there is event which always come. or say nothing happen to the socket including the error. if so the thread will block here. of course we can set stop even to exit thread, but I think we didn't have the chance to leave the block for other thing.
can you help me out? thx
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I'm afraid i don't understand what exactly it is you are asking. The wait can happen because, as you stated, the exit event can be signaled and the thread will drop out and terminate. This is functionality you wouldn't want to use if you all processing was done in the main thread. I doubt very seriously i have answered your question so if you could try to perhaps rephrase directly what it is you would like to know i can try to better help you out.
Joseph Dempsey joseph_r_dempsey@yahoo.com
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
My compiler does NOT recognize WSAEVENT.
So the following line does NOT compile: WSAEVENT hEvent = WSA_INVALID_EVENT;
Does anyone have any ideas?
Thanks. Jerry
Jerry
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
I have the following code. It detects an FD_ACCEPT message properly, but when it heads back to wait for another event, it always outputs the "Event Number 0" (the last "else" in the function) then heads back up the loop and resumes waiting. When it resumes waiting, I can connect again, to have the same process repeat. I tested my message sending code with a regular blocking socket and it worked fine. Any thoughts on what I'm doing wrong, how come I'm not getting FD_READ when I send data?
Thanks,
Rob
[code]================================================================= WSAEVENT hEvent1 = WSACreateEvent(); WSAEventSelect(listeningSocket, hEvent1, FD_READ | FD_WRITE | FD_CONNECT | FD_ACCEPT); SOCKET m_theClient; WSANETWORKEVENTS hConnectEvent;
while (1) { cout<<"WAITING"<<endl; WSAWaitForMultipleEvents(1, &hEvent1, FALSE, INFINITE, FALSE); WSAEnumNetworkEvents(listeningSocket, hEvent1, &hConnectEvent); if ((hConnectEvent.lNetworkEvents & FD_ACCEPT) && (hConnectEvent.iErrorCode [FD_ACCEPT_BIT] == 0) ) { struct sockaddr_in clientSockAddr; int clientSockAddrSize = sizeof(clientSockAddr); m_theClient = accept(listeningSocket, (struct sockaddr *)&clientSockAddr, (int *)&clientSockAddrSize); //if errors found handle them, else cout<<"Event: "<<FD_ACCEPT<<"\nAccepted a connection from "<<inet_ntoa (clientSockAddr.sin_addr)<<" "<<ntohs(clientSockAddr.sin_port)<<endl; }
else if ((hConnectEvent.lNetworkEvents & FD_READ) && hConnectEvent.iErrorCode[FD_READ_BIT] == 0) { cout<<"READ"<<endl; }
else if ((hConnectEvent.lNetworkEvents & FD_WRITE) && hConnectEvent.iErrorCode[FD_WRITE_BIT] == 0) { cout<<"WRITE"<<endl; }
else if ((hConnectEvent.lNetworkEvents & FD_CONNECT) && hConnectEvent.iErrorCode[FD_CONNECT_BIT] == 0) { cout<<"Connect!"<<endl; } else cout<<"Event Number was: "<<hConnectEvent.lNetworkEvents<<endl; } WSACloseEvent(hEvent1); closesocket(m_theClient);
return 0; ===================================================================[/code]
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Once you get an accepted socket you aren't doing anything with it to allow it to process network events. You still may have the association on your litening socket but there is nothing for the newly created socket. You need to do another ::WSAEventSelect(...) on the new socket m_theClient and associate the FD_READ event. You will need to add a new event handle to an array and incremement the number of handles you are waiting on in the WSAWaitForMultipleEvents functions. Hope this helps.
-- Joe
Joseph Dempsey joseph_r_dempsey@yahoo.com "What?, Of course its fireproof! ...... < 10 Minutes later in the ER > Sorry..."
How about,
"Bugs?, of course there are not bugs .... < 3 weeks after Production Release > Sorry..."
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
lol - I "just" figured that out as you posted and I was about to say the same thing. I found some french website with some source code - don't let my username fool you - I'm by no means french nor canadian.
Yes, that was exactly my problem. This isn't the case for my project, but for a general question, if I wanted to have say an up to 64 connections, could I use the same WSAEvent information for all clients?
Edit: here's the french website with some informative source code http://www.cppfrance.com/article.aspx?Val=1287
It appears that with their setup you can have multiple clients, and I could in my program as well, mainly because I forgot to close some stuff.
Very useful tutorial - thank you!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
i am not 100% on what you mean here but try this:
You need a seperate event for each client connection. That will support up to the 64 handle limit - 1 for your listening event. So you can have a total of 64 event per call to WaitMultObj call. If you want more than that i would suggest you start looking at I/O completion ports or other such technology as you are seriously pushing the limits of what the network event architecture was meant to do.
-- Joe
Joseph Dempsey joseph_r_dempsey@yahoo.com "What?, Of course its fireproof! ...... < 10 Minutes later in the ER > Sorry..."
How about,
"Bugs?, of course there are not bugs .... < 3 weeks after Production Release > Sorry..."
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi, thanks for the explanation. I've started to learn a new thing...
In my code I've implemented a server side socket, and I set the event select as:
WSAEVENT hTheSocketEventHandle = WSA_INVALID_EVENT; WSANETWORKEVENTS wsaThisSocketEvents;
hTheSocketEventHandle = WSACreateEvent(); WSAEventSelect( m_sTheSocket, hTheSocketEventHandle, FD_ACCEPT|FD_READ|FD_CLOSE);
And then, this code works properly: int nRetcode = ::WSAWaitForMultipleEvents(1, &hTheSocketEventHandle, FALSE, INFINITE, FALSE);
nRetcode = WSAEnumNetworkEvents(m_sTheSocket, hTheSocketEventHandle, &wsaThisSocketEvents); if ( nRetcode != SOCKET_ERROR ) { // This part of the code executes in the accept, read and close events.
// The problem is that here, the wsaThisSocketEvents.lNetworkEvents field // is no 0 only in the Accept!!!! }
I do not know what may I'm doing wrong... Any advise or suggestion will be appreciated, a lot.
Pablo
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
any number of things could cause that problem. What you need to do is to make a call to WSAGetLastError() to get the specific error code and then either look it up in msdn or programatically do a FormatMessage(..) on it and then log the result to determine exactly what is happening. If you still can't figure it out the post back here once you know the error code.
Joseph Dempsey joseph_r_dempsey@yahoo.com "Software Engineering is a race between the programmers, trying to make bigger and better fool-proof software, and the universe trying to make bigger fools. So far the Universe in winning." --anonymous
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Thanks for your reply.
In fact, I received no error. That's a good thing  Now, I know what the problem is. I'm trying to make a AsyncSocket class similar to the MFC. So, in the accept function I create a new socket, but I didn't set the networks flags to catch. So, I did it, and no problem.
So, thanks a lot for your docu.
Pablo
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi, thanks for the explanation. I've started to learn a new thing...
In my code I've implemented a server side socket, and I set the event select as:
WSAEVENT hTheSocketEventHandle = WSA_INVALID_EVENT; WSANETWORKEVENTS wsaThisSocketEvents;
hTheSocketEventHandle = WSACreateEvent(); WSAEventSelect( m_sTheSocket, hTheSocketEventHandle, FD_ACCEPT|FD_READ|FD_CLOSE);
And then, this code works properly: int nRetcode = ::WSAWaitForMultipleEvents(1, &hTheSocketEventHandle, FALSE, INFINITE, FALSE);
nRetcode = WSAEnumNetworkEvents(m_sTheSocket, hTheSocketEventHandle, &wsaThisSocketEvents); if ( nRetcode != SOCKET_ERROR ) { // This part of the code executes in the accept, read and close events.
// The problem is that here, the wsaThisSocketEvents.lNetworkEvents field // is no 0 only in the Accept!!!! }
I do not know what may I'm doing wrong... Any advise or suggestion will be appreciated, a lot.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
The code on the site you refer to is TERRIBLE!
Just because a guy writes a book and is ONLY trying to sell his book does not mean his code is any good. I have looked at his code and his book and both are TERRIBLE.
This is bad Winsock code in my opinion and i would NEVER recommend it to anyone!
It STINKS!
|
| Sign In·View Thread·PermaLink | 2.00/5 |
|
|
|
 |
|
 |
I found a good sample of using network events. Take a look at the "CSecureEvtSyncSocket" class in this sample:
SecureSOAP Sample: Implements a Secure SOAP Communication (HTTPS)
In your article, you mentioned that "it is not possible to use two different event objects to listen for different network events". What do you mean by that? The sample I found worked great with multiple events.
When I added the listen and accept methods to the sample, I was having some trouble with the waiting for either an FD_ACCEPT or FD_CLOSE event. I created a separate thread to wait for incoming connections and tried using WaitForMultipleObjects() but it never completes even after I open a connection with a client program. The only thing that has worked so far is WaitForSingleObject() with the FD_ACCEPT event. But then I can't detect when the socket is closed by the client or server. Any suggestions?
What references did you find most useful (books, articles, web pages, MSDN info, etc)? I was hoping that the "Network Programming for Microsoft® Windows®, Second Edition" book by Anthony Jones would be the most helpful... Any other recommendations?
Thanks, Jerry
|
| Sign In·View Thread·PermaLink | 3.67/5 |
|
|
|
 |
 | WSA  shotgun | 5:29 20 Jul '02 |
|
 |
newbie here so please be kind... this works great for me, WSADATA wsaData; sockaddr_in local; int wsaret=WSAStartup(0x202,&wsaData); this doesn't, WSADATA wsaData; LPFN_WSASTARTUP wsaret = (LPFN_WSA_STARTUP)::GetProcAddress(::LoadLibrary("WS2_32.DLL"), "WSAStartup"); wsaret(0x0202, &wsaData); I get an error that LPFN_WSASTARTUP is undeclared which of course starts a whole bunch of errors, is there an include file? Any helps really appreciated.
shotgun
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
 | Re: WSA  Joseph Dempsey | 19:01 21 Jul '02 |
|
 |
before you include winsock2.h you need to put this code.
#ifndef INCL_WINSOCK_API_TYPEDEFS #define INCL_WINSOCK_API_TYPEDEFS 1 #endif
// then include: #include <winsock2.h>
also any header you include ( mainly a concern in your stdafx.h file ) that may suck in the winsock.h file you should do a:
#define _WINSOCKAPI_
// then do main includes like ( depending on application flavor ): #include <atlbase.h>
// or
#include <windows.h>
// or
#include <afxwin.h>
Hope this takes care of your problem.
Joseph Dempsey jdempsey@cox.rr.com Joseph.Dempsey@thermobio.com "Software Engineering is a race between the programmers, trying to make bigger and better fool-proof software, and the universe trying to make bigger fools. So far the Universe in winning." --anonymous
|
| Sign In·View Thread·PermaLink | 2.00/5 |
|
|
|
 |
|
|
 |
|
|