Bitty HTTP

Development » Waiting on Sockets

1Waiting on a socket

Shows how to wait for traffic on the socket instead of polling. This is mainly useful when running under an operating system instead of directly on the metel.

We wait by having the main loop ask for the active sockets so we can use select() or one of the other handles.

Files

FileServer.c

The file server is setup to just send a basic page as this example works mainly in the main.c file.

struct FileInfo m_Files[]= { /* Filename, Dynamic, Cookies, Gets, Posts, Callback */ {"/",false,NULL,NULL,NULL,File_Root}, {"/SomeStyle.css",false,NULL,NULL,NULL,File_SomeStyle}, {"/quit.html",true,NULL,NULL,NULL,File_Quit}, };
At the bottom we have the code that handles sending the static page.
const char RootHTML[]= "<!DOCTYPE html>" "<html>" "<head>" "<title>Bitty HTTP - Root</title>" "<link rel='stylesheet' href='/SomeStyle.css'>" "</head>" "<body>" "<div id='top'>Bitty HTTP Example - Root</div>" "<div id='quitbttn'><a href='/quit.html'>QUIT</a></div>" "<div id='content'>" "Wait example<br/>" "</div>" "<div id='bottom'></div>" "</body>" "</html>"; void File_Root(struct WebServer *Web) { WS_WriteWhole(Web,RootHTML,sizeof(RootHTML)-1); }

main.c

The main has it's main loop changed to wait on the sockets that the web server currently have open.

int main(void) { t_ElapsedTime Waiting2End; t_ConSocketHandle OSHandles[WS_OPT_MAX_CONNECTIONS+1]; fd_set rfds; int retval; int MaxFD; int r; int HandleCount;

First there are some new variables:

OSHandles[] is used to hold the socket handles that are currently open. This has the same number as WS_OPT_MAX_CONNECTIONS plus one for the listening socket. We will fill this array in by calling WS_GetOSSocketHandles().

rfds is the set of OS handles to wait on. This is filled in using FD_SET() with each the socket handles that where returned in OSHandles[].

retval is the return value from the select() it's self. We only print out an error if select() returns an error

MaxFD is the highest OS file handle that we found in the socket handles.

r is just a simple loop counter.

HandleCount is the number of socket handles that was returned by WS_GetOSSocketHandles().

SocketsCon_InitSocketConSystem(); WS_Init(); if(!WS_Start(3000)) { printf("Failed to start web server\n"); return 0; } printf("Waiting for connections on port 3000\n"); g_Quit=false; while(!g_Quit) { WS_Tick();

This all remains unchanged

/* Wait for traffic */ FD_ZERO(&rfds); /* What handles are open may change each loop, so we think it all */ HandleCount=WS_GetOSSocketHandles(OSHandles);

We have replaced the usleep(1000); with code to get the active sockets and then wait on them.

The first thing we do is normal select() handing such has zeroing the rfds variable.

We then call WS_GetOSSocketHandles() to get the active sockets. This will fill in the OSHandles[] array with the socket handles we will waiting on. The web server may have up to WS_OPT_MAX_CONNECTIONS open, or none of them (depending on what requests are being processed) the WS_GetOSSocketHandles() function returns the number of handles it filled in.

WS_GetOSSocketHandles() uses t_ConSocketHandle as the type data for a OS socket handle. This type will depend on what a socket handle on the OS being used is. This is defined in SocketsCon.h. This allows the system to return a complex type such as a structure as a socket handle.

In this example it is a Unix style handle which is a simple int.

MaxFD=0; for(r=0;r<HandleCount;r++) { if(OSHandles[r]>MaxFD) MaxFD=OSHandles[r]; FD_SET(OSHandles[r],&rfds); }

Next we need to find the highest socket handle number to pass into select(). We loop through all the handles returned to us updating MaxFD if the new handle is bigger than the old MaxFD. We also need to use FD_SET() to setup rfds.

retval=select(MaxFD+1,&rfds,NULL,NULL,NULL); if(retval<0) printf("select() error\n");

At this point we call the select that will wait forever for something to happen on one of the sockets.

If the return value from select() is negative then we just print an error message and continue. You would likely want to handle the error here.

} printf("Quiting...\n"); /* Run the web server for a while so we can send any "finished" page */ Waiting2End=ReadElapsedClock(); while(ReadElapsedClock()-Waiting2End<3) WS_Tick(); WS_Shutdown(); SocketsCon_ShutdownSocketConSystem(); return 0; }

The shut down code remains the same as before.