The third part of this
Winsock tutorial provides a useful way to handle sockets by using an Event based model. This
model uses the CreateEvent function to create an event object, which can be made to
wait using WSAWaitForMultipleEvents for the network events. There
is also an article on Winsock
select model.
When
some network event occurs in relation to the socket, the above
function (WSAWaitForMultipleEvents ) returns
immediately with the event type that occured. Till that point,
it blocks the execution at the particular thread. Here are the type of events that are returned and used for
manipulation of the various network states.
| |
FD_READ
|
Data is to be read
|
|
FD_WRITE
|
Data is to be sent
|
|
FD_ACCEPT
|
Socket is to be accepted
|
|
FD_CLOSE
|
Socket is to be closed
|
The initial steps are to create the socket, bind and then associate it with an event object using WSAEventSelect. The event object will be created with a capability for doing a manual reset.
//
...
Create the socket
HANDLE hEvent = WSACreateEvent();
WSAEventSelect(Socket,hEvent,FD_ACCEPT|FD_CLOSE);
//
The event object handle hEvent will be used to wait for any network event to occur. The function
WSAWaitForMultipleEvents is used for this purpose. There is one draw back to this model. The WSAWaitForMultipleEvents can accept a maximum of 64 sockets per thread only. If more sockets are needed, then more threads have to be created.
Let us look at some sample code using
WSAEventSelect.
If you look at the following program, there are two
threads which form the basis for the whole program. One is the
server thread and the next is the client thread. The Server
thread starts the Network server by create, bind and listening
on a particular port. Whenever any new connections are coming
in, it simply accepts the new connections in a new socket
handle and passes it on to the client thread.
Winsock tutorial - Steps for creating the application:
1. Create a new project of type win32 application. Select empty project and click finish.
2. After creating the application, click on Menu -->Project --> Add to Project -->New and add .cpp file and .h file. Better
if both of them have same name
3. Include the files windows.h and winsock.h. We also need Stdio.h and afxtempl.h for some other purposes.
4.The logic behind this winsock tutorial sample program is to create an winsock application which can accept multiple
clients. We do this by using the windows multi threading feature.
5. We need certain global handles and declarations as follows for this winsock tutorial sample program.
HANDLE hStopEvent;
HANDLE NetworkEvent;
HANDLE hServerThread;
int clientno;
CArray<HANDLE,HANDLE> threadArray; //Maintains a list of connected clients
6.Create a function named StartServer, which can be called in a thread. The StartServer routine in this winsock tutorial
does the following.
- Creates a socket
- Binds it to a port number
- Listens for incoming connections
- Whenever a client connects, it accepts the connection and spawns a client thread
- The socket is added to the threadarray.
7. The client thread function in this Winsock
tutorial, when called does the following.
Waits for the network events related to the socket.
- Whenever a network event occurs, it checks for the type of event
- If it is a FD_READ event, it receives the data. This is where most of the applications will need to write their logic
viz., parsing, reply etc.,
- If it is a FD_WRITE, it sends data
- If it is a FD_CLOSE, it closes the connection and the socket is deleted from the threadarray.
DWORD WINAPI ClientThread(LPVOID thread_data)
{
SOCKET sClient;
WSANETWORKEVENTS NetworkEvents;
sClient =(SOCKET &)thread_data; //Client socket for winsock tutorial
while(true)
{
if ((Event = WSAWaitForMultipleEvents(1, &NetworkEvent, FALSE,WSA_INFINITE, FALSE))
== WSA_WAIT_FAILED)
return 0;
if (WSAEnumNetworkEvents(sClient ,NetworkEvent, &NetworkEvents) == SOCKET_ERROR)
return 0;
if (NetworkEvents.lNetworkEvents & FD_READ)
{
if (NetworkEvents.lNetworkEvents & FD_READ &&
NetworkEvents.iErrorCode [FD_READ_BIT] != 0)
{
printf("FD_READ failed with error %d\n", NetworkEvents.iErrorCode[FD_READ_BIT]);
}
else
{
//Winsock tutorial - this is where the actual logic usually goes
? recvLength = recv(sClient,str,200,0);
str[recvLength] = '\0';
printf(" Winsock Tutorial Data Received using Event Object:\n",str);
printf("%s\n",str);
.....
}
}
}
Note:
The socket programs in MFC need the library ws2_32.lib to be
referenced before linking. Otherwise the VC++ linker throws
errors.
Find the sample
project here.