Winsock Tutorial 4

Non-Blocking Sockets in TCP/IP (The Server)

This tutorial is a designed to be a companion to our previous non-blocking client tutorial. The non-blocking server is ideal for instances where the programmer requires the server to process other information behind the scenes, rather than sit around doing nothing.


Prerequisites

Project type: Console
Include files: winsock2.h
Library files: ws2_32.lib



The Server

Once again, the layout of our server is very similar to the one we used for our 'blocking' server in tutorial 2. If you forget how this worked, it is probably worth reviewing as we can omit explanations such as initialising winsock etc...

As with our 'blocking' server the first steps are the same;

1) Initialise Winsock
2) Create a Socket
3) Fill out a SOCKADDR_IN struct
4) Listen on our socket
5) Accept a connection from the client

From here things change from our 'blocking server'. As with our 'non-blocking' client we set our socket to 'non-blocking' mode.

u_long iMode=1;
ioctlsocket(Socket,FIONBIO,&iMode);

From here we can now go into our main loop.

In our tutorial example, all our server will be doing to sending a message ('Welcome to the server!') once every second.
for(;;)
{
	char *szMessage="Welcome to the server!\r\n";
	send(Socket,szMessage,strlen(szMessage),0);
						
	int nError=WSAGetLastError();
	if(nError!=WSAEWOULDBLOCK&&nError!=0)
{ std::cout<<"Winsock error code: "<<nError<<"\r\n"; std::cout<<"Client disconnected!\r\n"; // Shutdown our socket shutdown(Socket,SD_SEND); // Close our socket entirely closesocket(Socket); break; } Sleep(1000); }

If our client disconnects for some reason, WSAGetLastError() will return a value as to why or how the client disconnected. See Appendix - Winsock Error Codes in our tutorial section.


And once our loop is broken we need to clean up Winsock and return back to Windows.

So, that is all there is to it! We now have a fully working 'non-blocking' client server pair of applications.

The Full Code

#include <iostream>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
					
int main()
{
	WSADATA WsaDat;
	if(WSAStartup(MAKEWORD(2,2),&WsaDat)!=0)
	{
		std::cout<<"WSA Initialization failed!\r\n";
		WSACleanup();
		system("PAUSE");
		return 0;
	}
					
	SOCKET Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	if(Socket==INVALID_SOCKET)
	{
		std::cout<<"Socket creation failed.\r\n";
		WSACleanup();
		system("PAUSE");
		return 0;
	}
					
	SOCKADDR_IN serverInf;
	serverInf.sin_family=AF_INET;
	serverInf.sin_addr.s_addr=INADDR_ANY;
	serverInf.sin_port=htons(8888);
					
	if(bind(Socket,(SOCKADDR*)(&serverInf),sizeof(serverInf))==SOCKET_ERROR)
	{
		std::cout<<"Unable to bind socket!\r\n";
		WSACleanup();
		system("PAUSE");
		return 0;
	}
		
	listen(Socket,1);
					
	SOCKET TempSock=SOCKET_ERROR;
	while(TempSock==SOCKET_ERROR)
	{
		std::cout<<"Waiting for incoming connections...\r\n";
		TempSock=accept(Socket,NULL,NULL);
	}
				
	// If iMode!=0, non-blocking mode is enabled.
	u_long iMode=1;
	ioctlsocket(Socket,FIONBIO,&iMode);
					
	Socket=TempSock;
	std::cout<<"Client connected!\r\n\r\n";
					
	// Main loop
	for(;;)
	{
		char *szMessage="Welcome to the server!\r\n";
		send(Socket,szMessage,strlen(szMessage),0);
					
		int nError=WSAGetLastError();
		if(nError!=WSAEWOULDBLOCK&&nError!=0)
		{
			std::cout<<"Winsock error code: "<<nError<<"\r\n";
			std::cout<<"Client disconnected!\r\n";

			// Shutdown our socket
			shutdown(Socket,SD_SEND);

			// Close our socket entirely
			closesocket(Socket);

			break;
		}
			
		Sleep(1000);
	}

	WSACleanup();
	system("PAUSE");
	return 0;
}


Things to try

Try sending and receiving data to and from your server using the send() and recv() functions.

Additional informaton

For additional information we have provided the following links.

Microsoft (MSDN) - Getting started with Winsock
Microsoft (MSDN) - More information on the ioctlsocket() function

Next tutorial

Tutorial 5 - Error handling with Winsock