一个精简服务器



一个精简服务器


一个Web服务器并没有必要比我们前面章节中创建的简单服务器复杂。接受TCP/IP连接之后,Web服务器需要使用HTTP协议实现更深层的通信。

除了将处理连接的代码分隔到它自己的函数之外,下面列出的服务器代码几乎与简单服务器相同。这个函数处理来自网络浏览器的HTTP GETHEAD请求。程序会在本地目录webroot中查找浏览器请求的资源并将它发送给浏览器。如果不能找到文件,服务器会以404HTTP作为回应。您可能早已熟悉了这个响应,它的意思是文件没有找到File Not Found)。完整的源代码如下所示。

#include<stdio.h>

#include<fcntl.h>

#include<stdlib.h>

#include<string.h>

#include<sys/stat.h>

#include<sys/socket.h>

#include<netinet/in.h>

#include<arpa/inet.h>

#include"hacking.h"

#include"hacking-network.h"

#define PORT80   // the port users will be connectingto

#defineWEBROOT "./webroot" // the web server's root directory

voidhandle_connection(int, struct sockaddr_in *); // handle web requests

intget_file_size(int); // returns the filesize of open file descriptor

int main(void){

   int sockfd, new_sockfd, yes=1;

   struct sockaddr_in host_addr,client_addr;   // my address information

   socklen_t sin_size;

   printf("Accepting web requests on port%d\n", PORT);

   if ((sockfd = socket(PF_INET, SOCK_STREAM,0)) == -1)

      fatal("in socket");

   if (setsockopt(sockfd, SOL_SOCKET,SO_REUSEADDR, &yes, sizeof(int)) == -1)

      fatal("setting socket optionSO_REUSEADDR");

   host_addr.sin_family = AF_INET;      // host byte order

   host_addr.sin_port = htons(PORT);    // short, network byte order

   host_addr.sin_addr.s_addr = INADDR_ANY; //automatically fill with my IP

   memset(&(host_addr.sin_zero), '\0', 8);// zero the rest of the struct

   if (bind(sockfd, (struct sockaddr*)&host_addr, sizeof(struct sockaddr)) == -1)

      fatal("binding to socket");

   if (listen(sockfd, 20) == -1)

      fatal("listening on socket");

   while(1) {  // Accept loop

      sin_size = sizeof(struct sockaddr_in);

      new_sockfd = accept(sockfd, (structsockaddr *)&client_addr, &sin_size);

      if(new_sockfd == -1)

         fatal("acceptingconnection");

      handle_connection(new_sockfd,&client_addr);

   }

   return 0;

}

/* Thisfunction handles the connection on the passed socket from the

 * passed client address.  The connection is processed as a web request

 * and this function replies over the connectedsocket.  Finally, the

 * passed socket is closed at the end of thefunction.

 */

/*该函数处理所传递的套接字上的链接,该套接字来自于所传递的客户端地址。链接作为网络请求进行处理,并且该函数通过已连接的套接字进行回复。最后,在函数的末尾关闭所传递的套接字*/

voidhandle_connection(int sockfd, struct sockaddr_in *client_addr_ptr) {

   unsigned char *ptr, request[500],resource[500];

   int fd, length;

   length = recv_line(sockfd, request);

   printf("Got request from %s:%d\"%s\"\n", inet_ntoa(client_addr_ptr->sin_addr),ntohs(client_addr_ptr->sin_port), request);

   ptr = strstr(request, " HTTP/");// search for valid looking request

   if(ptr == NULL) { // then this isn't validHTTP

      printf(" NOT HTTP!\n");

   } else {

      *ptr = 0; // terminate the buffer at theend of the URL

      ptr = NULL; // set ptr to NULL (used toflag for an invalid request)

      if(strncmp(request, "GET ", 4)== 0)  // get request

         ptr = request+4; // ptr is the URL

      if(strncmp(request, "HEAD ", 5)== 0) // head request

         ptr = request+5; // ptr is the URL

      if(ptr == NULL) { // then this is not arecognized request

         printf("\tUNKNOWNREQUEST!\n");

      } else { // valid request, with ptrpointing to the resource name

         if (ptr[strlen(ptr) - 1] == '/')  // for resources ending with '/'

            strcat(ptr,"index.html");     // add'index.html' to the end

         strcpy(resource, WEBROOT);     // begin resource with web root path

         strcat(resource, ptr);         // and join it with resource path

         fd = open(resource, O_RDONLY, 0); //try to open the file

         printf("\tOpening \'%s\'\t",resource);

         if(fd == -1) { // if file is not found

            printf(" 404 NotFound\n");

            send_string(sockfd, "HTTP/1.0404 NOT FOUND\r\n");

            send_string(sockfd, "Server:Tiny webserver\r\n\r\n");

            send_string(sockfd,"<html><head><title>404 Not Found</title></head>");

            send_string(sockfd,"<body><h1>URL notfound</h1></body></html>\r\n");

         } else {      // otherwise, serve up the file

            printf(" 200 OK\n");

            send_string(sockfd, "HTTP/1.0200 OK\r\n");

            send_string(sockfd, "Server:Tiny webserver\r\n\r\n");

            if(ptr == request + 4) { // thenthis is a GET request

               if( (length = get_file_size(fd))== -1)

                  fatal("getting resourcefile size");

               if( (ptr = (unsigned char *)malloc(length)) == NULL)

                  fatal("allocating memoryfor reading resource");

               read(fd, ptr, length); // readthe file into memory

               send(sockfd, ptr, length,0);  // send it to socket

               free(ptr); // free file memory

            }

            close(fd); // close the file

         } // end if block for file found/notfound

      } // end if block for valid request

   } // end if block for valid HTTP

   shutdown(sockfd, SHUT_RDWR); // close thesocket gracefully

}

/* Thisfunction accepts an open file descriptor and returns    

 * the size of the associated file.  Returns -1 on failure.

 */

intget_file_size(int fd) {

   struct stat stat_struct;

   if(fstat(fd, &stat_struct) == -1)

      return -1;

   return (int) stat_struct.st_size;

}

函数handle_connection使用strstr()函数在请求缓存中查找子字符串HTTP/。函数strstr()返回一个指向子字符串的指针这个子串正好在请求报文的末尾。字符串在这里终止,并且请求的HEAD和GET被看作可处理的请求。HEAD请求会返回报头,GET请求还会返回请求的资源(如果能够找到)。

下面的代码已经在目录webroot中放置了文件index.html和index.jpg,然后编译了程序tinyweb。绑定小于1024的任意一个端口时,都需要root权限,所以程序是setuidroot并且可以执行。服务器的调试输出显是示了—个Web浏览器对http://127.0.0.1请求结果。

[root@localhost ~]# ls -l /tmp/webroot/

total 20

-rw-r--r-- 1 root root 1406 Feb  6 06:40 favicon.ico

-rw-r--r-- 1 root root  251 Feb  6 06:35 index.html

-rw-r--r-- 1 root root 12046 Feb  6 05:32 index.jpg

[root@localhost ~]# cat /tmp/webroot/index.html

<html>

<head><title>A samlp webpage</head>

<body bgcolor="#000000"text="#ffffff">

<center>

<h1>This is a sample webpage</h1>

...and here is some sample text<br>

<br>

.. and even a samle image:<br>

<img src="index.jpg"><br>

</center>

</body>

</html>

地址127.0.0.1是一个特殊的回环地址,它将路径导向本地计算机。初始请求从Web服务器获取index.html,该文件随后又请求image.jpg。此外,浏览器自动请求favicon.ico以尝试为网页获取一个图标。下图显示了浏览器中这个请求的结果。

下一篇文章介绍网络底层的知识。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值