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_CLOSESocket is to be closed FD_ACCEPTSocket is to be accepted FD_WRITEData is to be sent
FD_READ | Data is to be read | |
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 %dn”, NetworkEvents.iErrorCode[FD_READ_BIT]);
}
else
{
//Winsock tutorial – this is where the actual logic usually goes
? recvLength = recv(sClient,str,200,0);
str[recvLength] = ”;
printf(” Winsock Tutorial Data Received using Event Object:n”,str);
printf(“%sn”,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.