|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionWell, 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 AssumptionsThere are some assumptions that I am making about the readers of this article. They are:
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):
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 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, 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 NotificationsNow 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 //Assume m_listen and m_data are both vaild sockets 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
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( //checks to see if this was the event that occurred (wsaConnectEvents.lNetworkEvents & FD_ACCEPT) && //ensures that there was no error (wsaConnectEvents.iErrorCode[FD_ACCEPT_BIT] == 0) ) { /* .... //Handle Processing here .... */ }
This manner of checking can be done for each ConclusionI 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.
|
||||||||||||||||||||||