Implementing a Simple Web Server

The sample program web_server.c uses a utility function read_file to read a local file and return the contents of the file as one large character buffer (variable ret_buf). The variable error_return has the value of an HTML formatted error message.

The following code implements the read_file function for reading the contents of a local file into a buffer: char ret_buf[32768];

char * error_return = "<HTML>\n<BODY>File not found\n</BODY>\n</HTML>";

if (DEBUG) printf("%d bytes read from file %s\n", i, cp); if (i == 0) { fclose(f); return error_return; } ret_buf[i] = '\0'; fclose(s); return ret_buf;

In the web_server.c example, the function main opens up a socket for listening for service requests in the usual way. web_server.c checks the error codes for all system calls; these checks are left out in the following short description of how the Web server works. The following code is similar to the server socket setup code in the example server.c:

int sock;

int serverSocket;

struct sockaddr_in serverAddr;

struct sockaddr_in clientAddr;

int clientAddrSize;

struct hostent* entity;

serverSocket = socket(AF_INET, SOCK_STREAM, 0); serverAddr.sin_family = AF_INET;

serverAddr.sin_port = htons(port);

serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); memset(&(serverAddr.sin_zero), 0, 8);

19

O? t Rsq

£T>

The following call to bind associates this socket with the desired port number (from the variable port):

bind(serverSocket, (struct sockaddr*) &serverAddr, sizeof(struct sockaddr));

The following call to listen sets a limit of 10 queued requests, and indicates that the program is now ready to accept incoming service requests:

listen(serverSocket, 10); // allow 10 queued requests

The example in web_server.c is now ready to loop, waiting for incoming connections. A new socket is opened for each incoming service request; the data for a service request is read, the request is processed with data returned to the client, and finally the temporary socket (variable sock)is closed.

The following code fragment from the web_server.c example implements a processing loop that waits for incoming client request: while (1) {

clientAddrSize = sizeof(struct sockaddr_in); do sock = accept(serverSocket,

(struct sockaddr*) &clientAddr, &clientAddrSize); while ((sock == -1) && (errno == EINTR)); if (sock == -1) {

entity = gethostbyaddr((char*) &clientAddr.sin_addr, sizeof(struct in_addr), AF_INET); if (DEBUG) printf("Connection from %d\n", inet_ntoa((struct in_addr) clientAddr.sin_addr));

if (i == -1) break; if (recvBuffer[i - 1] != '\n') break; recvBuffer[i] = '\0'; if (DEBUG) {

printf("Received from client: %s\n", recvBuffer);

// call a separate work function to process request: cbuf = read_file(recvBuffer, totalReceived); size = strlen(cbuf); totalSent = 0; do {

Chapter 19

bytesSent = send(sock, cbuf + totalSent, strlen(cbuf + totalSent), 0); if (bytesSent == -1) break; totalSent += bytesSent; } while (totalSent < size);

if (DEBUG) printf("Connection closed by client.\n"); close(sock);

This code is very similar to the example server.c except here, data received from the client is interpreted as a request for a local file. The requested local file is read into a buffer, and the buffer is sent back to the client.

Was this article helpful?

0 0

Post a comment