一个简单Web Server 的实现


下了 Ani-server 的源码, 代码不过几百行, 已经有一个基本 web server 的功能.

参照其思路, 自己实现了下, 有点意思.

基本思路:

1)取得一 socket 的 fd -->  bind --> listen -->select --> accept, 

    得到一 cli_fd, 通过它可以和请求服务的浏览器通信

2)从 cli_fd 读取数据, 判断是否是 http 的 GET, 获得被请求的文件, 将文件数据写入 cli_fd.

源码:

  1. /*  
  2.  * author: dengzhaoqun 
  3.  * date: 2011/07/21 
  4.  * platform: linux 
  5.  */  
  6. #include <sys/select.h>   
  7. #include <stdio.h>   
  8. #include <sys/types.h>   
  9. #include <sys/socket.h>   
  10. #include <stdlib.h>   
  11. #include <string.h>   
  12. #include <arpa/inet.h>   
  13. #include <netinet/in.h>   
  14. #include <fcntl.h>   
  15. #include <sys/stat.h>   
  16. #include <unistd.h>   
  17.   
  18. #define DEFAULT_PAGE "index.html"   
  19. #define WEB_ROOT "/home/xiaodeng/aniroot"   
  20.   
  21. void connection(int fd);  
  22. int recv_new(int fd, char *str);  
  23. void send_new(int fd, char *str);  
  24. int get_file_size(int fd);  
  25.   
  26. int main()  
  27. {  
  28.     int ser_fd, cli_fd, max_fd, fd;  
  29.     struct sockaddr_in ser_addr;  
  30.     struct sockaddr_in cli_addr;  
  31.     int ser_addr_len, cli_addr_len;  
  32.     fd_set readfds, master;  
  33.     int ret;  
  34.   
  35.   
  36.     ser_fd = socket(AF_INET, SOCK_STREAM, 0);  
  37.     if(ser_fd == -1)  
  38.     {  
  39.         perror("socket failed");  
  40.         exit(1);  
  41.     }  
  42.   
  43.     ser_addr_len = sizeof(ser_addr);  
  44.     memset(&ser_addr, 0, ser_addr_len);  
  45.   
  46.     ser_addr.sin_family = AF_INET;  
  47.     ser_addr.sin_addr.s_addr = inet_addr("127.0.0.1");  
  48.     ser_addr.sin_port = htons(80);  
  49.   
  50.     ret = bind(ser_fd, (struct sockaddr *)&ser_addr, ser_addr_len);  
  51.     if(ret == -1)  
  52.     {  
  53.         perror("bind failed");  
  54.         exit(1);  
  55.     }  
  56.   
  57.     listen(ser_fd, 5);  
  58.   
  59.     FD_ZERO(&master);  
  60.     FD_SET(ser_fd, &master);  
  61.     max_fd = ser_fd;  
  62.   
  63.     while(1)  
  64.     {  
  65.         readfds = master;  
  66.         ret = select(max_fd + 1, &readfds, 0, 0, 0);  
  67.         if(ret == -1)  
  68.         {     
  69.             perror("select failed");  
  70.         }  
  71.         else  
  72.         {  
  73.             for(fd = 0; fd < max_fd + 1; fd ++)  
  74.             {  
  75.                 if(FD_ISSET(fd, &readfds))  
  76.                 {  
  77.                     if(fd == ser_fd)  
  78.                     {  
  79.                         cli_addr_len = sizeof(cli_addr);  
  80.                         memset(&cli_addr, 0, cli_addr_len);  
  81.                         cli_fd = accept(ser_fd,  
  82.                                     (struct sockaddr *)&cli_addr,  
  83.                                 (socklen_t *)&cli_addr_len);  
  84.                         if(cli_fd > max_fd)  
  85.                         {  
  86.                             max_fd = cli_fd;  
  87.                         }  
  88.   
  89.                         FD_SET(cli_fd, &master);  
  90.                     }  
  91.                     else  
  92.                     {  
  93.                         connection(fd);  
  94.                         FD_CLR(fd, &master);  
  95.                     }  
  96.                 }  
  97.             }  
  98.         }  
  99.     }  
  100.   
  101. }/* main() */  
  102.   
  103.   
  104.   
  105. void  
  106. connection(int fd)  
  107. {  
  108.     char request[1000], resource[1000], *ptr;  
  109.     int ret;  
  110.     int page_fd;  
  111.   
  112.     ret = recv_new(fd, request);  
  113.       
  114.     ptr = strstr(request, " HTTP/");  
  115.     if(ptr == NULL)  
  116.     {  
  117.         perror("Not HTTP request");  
  118.     }  
  119.     else  
  120.     {  
  121.         *ptr = 0;  
  122.         ptr = NULL;  
  123.   
  124.         if(strncmp(request, "GET ", 4) == 0)  
  125.         {  
  126.             ptr = request + 4;  
  127.         }  
  128.         if(strncmp(request, "HEAD ", 5) == 0)  
  129.         {  
  130.             ptr = request + 5;  
  131.         }  
  132.         if(ptr == NULL)  
  133.         {  
  134.             perror("Unknown Request. \n");  
  135.         }  
  136.         else  
  137.         {  
  138.             memset(resource, 0, sizeof(resource));  
  139.             strncpy(resource, WEB_ROOT, sizeof(resource));  
  140.             strncat(resource, ptr, sizeof(resource) - sizeof(WEB_ROOT) -1);  
  141.             if(ptr[strlen(ptr) -1] == '/' )  
  142.             {  
  143.                 strncat(resource, DEFAULT_PAGE, sizeof(resource)  
  144.                         - strlen(resource)  
  145.                         - sizeof(DEFAULT_PAGE)  
  146.                         - 1);  
  147.             }  
  148.   
  149.             if((page_fd = open(resource, O_RDONLY)) == -1)  
  150.             {  
  151.                 perror("open failed, file not found");  
  152.                 send_new(fd, "HTTP/1.1 404 NOT FOUND\r\n");  
  153.                 send_new(fd, "<html><head>404 NOT FOUND</head>");  
  154.                 send_new(fd, "<body>Sorry, NOT FOUND</body></html>");  
  155.                 close(fd);  
  156.             }  
  157.             else  
  158.             {  
  159.                 int file_size;  
  160.                   
  161.                 memset(request, 0, sizeof(request));  
  162.                 file_size = get_file_size(page_fd);  
  163.                 read(page_fd, request, file_size);  
  164.                   
  165.                 send_new(fd, "HTTP/1.1 200 OK\r\n");  
  166.                 send_new(fd, request);  
  167.                 close(fd);  
  168.             }  
  169.         }  
  170.     }  
  171. }/* connection() */  
  172.                   
  173.   
  174. void  
  175. send_new(int fd, char *str)  
  176. {  
  177.     int len;  
  178.     len = strlen(str);  
  179.     write(fd, str, len);  
  180. }/* send_new() */  
  181.   
  182. int  
  183. get_file_size(int fd)  
  184. {  
  185.     struct stat buf;  
  186.       
  187.     fstat(fd, &buf);  
  188.   
  189.     return(buf.st_size);  
  190. }/* get_file_size() */  
  191.   
  192. int  
  193. recv_new(int fd, char *str)  
  194. {  
  195.     char *p = str;  
  196.     int flag;  
  197.   
  198.     flag = 0;  
  199.     while(1)  
  200.     {  
  201.         read(fd, p, 1);  
  202.         if(*p == '\r')  
  203.             flag = 1;  
  204.         if( flag && (*p == '\n'))  
  205.         {  
  206.             flag = 0;  
  207.             break;  
  208.         }  
  209.         p ++;  
  210.     }  
  211.     *(p-1) = '\0';  
  212.   
  213.     return(strlen(str));  
  214. }/* recv_new() */  

编译后运行, 在浏览器中输入 "http://localhost/filename.html" , 即可在浏览器中显示 WEB_ROOT 目录下的相应 html 文件.

相关内容