socket通信之http-server

来源:互联网 发布:淘宝助理导出宝贝 编辑:程序博客网 时间:2024/06/05 01:19
  1. #include <stdarg.h>  
  2. #include <errno.h>  
  3. #include <stdio.h>  
  4. #include <fcntl.h>  
  5. #include <unistd.h>  
  6. #include <string.h>  
  7. #include <time.h>  
  8. #include <sys/types.h>  
  9. #include <sys/stat.h>  
  10. #include <dirent.h>  
  11. #include <errno.h>  
  12. #include <netinet/in.h>  
  13. #include <sys/socket.h>  
  14. #include <resolv.h>  
  15. #include <arpa/inet.h>  
  16. #include <stdlib.h>  
  17. #include <signal.h>  
  18. #include <getopt.h>  
  19.   
  20. //#define DEFAULTIP "127.0.0.1"  
  21. #define DEFAULTIP "192.168.1.33"  
  22. #define DEFAULTPORT "80"  
  23. #define DEFAULTBACK "10"  
  24. #define DEFAULTDIR "/home"  
  25. #define DEFAULTLOG "/tmp/http-server.log"  
  26.   
  27. void prterrmsg(char *msg);  
  28. #define prterrmsg(msg)        { perror(msg); abort(); }  
  29. void wrterrmsg(char *msg);  
  30. #define wrterrmsg(msg)        { fputs(msg, logfp); fputs(strerror(errno), logfp);fflush(logfp); abort(); }  
  31.   
  32. void prtinfomsg(char *msg);  
  33. #define prtinfomsg(msg)        { fputs(msg, stdout);  }  
  34. void wrtinfomsg(char *msg);  
  35. #define wrtinfomsg(msg)        {  fputs(msg, logfp); fflush(logfp);}  
  36.   
  37. #define MAXBUF        1024  
  38.   
  39. char buffer[MAXBUF + 1];  
  40. char *host = 0;  
  41. char *port = 0;  
  42. char *back = 0;  
  43. char *dirroot = 0;  
  44. char *logdir = 0;  
  45. unsigned char daemon_y_n = 0;  
  46. FILE *logfp;  
  47.   
  48. #define MAXPATH        150  
  49.   
  50. char *dir_up(char *dirpath)  
  51. {  
  52.     static char Path[MAXPATH];  
  53.     int len;  
  54.   
  55.     strcpy(Path, dirpath);  
  56.     len = strlen(Path);  
  57.     if (len > 1 && Path[len - 1] == '/')  
  58.         len--;  
  59.     while (Path[len - 1] != '/' && len > 1)  
  60.         len--;  
  61.     Path[len] = 0;  
  62.     return Path;  
  63. }  
  64.   
  65. void AllocateMemory(char **s, int l, char *d)  
  66. {  
  67.     *s = malloc(l + 1);  
  68.     bzero(*s, l + 1);  
  69.     memcpy(*s, d, l);  
  70. }  
  71.   
  72.   
  73.   
  74. void GiveResponse(FILE * client_sock, char *Path)  
  75. {  
  76.     struct dirent *dirent;  
  77.     struct stat info;  
  78.     char Filename[MAXPATH];  
  79.     DIR *dir;  
  80.     int fd, len, ret;  
  81.     char *p, *realPath, *realFilename, *nport;  
  82.    
  83.     len = strlen(dirroot) + strlen(Path) + 1;  
  84.     realPath = malloc(len + 1);  
  85.     bzero(realPath, len + 1);  
  86.     sprintf(realPath, "%s/%s", dirroot, Path);  
  87.     
  88.     len = strlen(port) + 1;  
  89.     nport = malloc(len + 1);  
  90.     bzero(nport, len + 1);  
  91.    sprintf(nport, ":%s", port);  
  92.   
  93.      
  94.     if (stat(realPath, &info)) {  
  95.         fprintf(client_sock,  
  96.                 "HTTP/1.1 200 OK\r\nServer: DAS by Chengang\r\nConnection: close\r\n\r\n<html><head><title>%d - %s</title></head>"  
  97.                 "<body><font size=+4>Linux 下目录访问服务器</font><br><hr width=\"100%%\"><br><center>"  
  98.                 "<table border cols=3 width=\"100%%\">", errno,  
  99.                 strerror(errno));  
  100.         fprintf(client_sock,  
  101.                 "</table><font color=\"CC0000\" size=+2>请向管理员咨询为何出现如下错误提示:\n%s %s</font></body></html>",  
  102.                 Path, strerror(errno));  
  103.         goto out;  
  104.     }  
  105.      
  106.     if (S_ISREG(info.st_mode)) {  
  107.         fd = open(realPath, O_RDONLY);  
  108.         len = lseek(fd, 0, SEEK_END);  
  109.         p = (char *) malloc(len + 1);  
  110.         bzero(p, len + 1);  
  111.         lseek(fd, 0, SEEK_SET);  
  112.         ret = read(fd, p, len);  
  113.         close(fd);  
  114.         fprintf(client_sock,  
  115.                 "HTTP/1.1 200 OK\r\nServer: DAS by Chengang\r\nConnection: keep-alive\r\nContent-type: application  
  116.         dir = opendir(realPath);  
  117.         fprintf(client_sock,  
  118.                 "HTTP/1.1 200 OK\r\nServer: DAS by Chengang\r\nConnection: close\r\n\r\n<html><head><title>%s</title></head>"  
  119.                 "<body><font size=+4>Linux 下目录访问服务器</font><br><hr width=\"100%%\"><br><center>"  
  120.                 "<table border cols=3 width=\"100%%\">", Path);  
  121.         fprintf(client_sock,  
  122.                 "<caption><font size=+3>目录 %s</font></caption>\n",  
  123.                 Path);  
  124.         fprintf(client_sock,  
  125.                 "<tr><td>名称</td><td>大小</td><td>修改时间</td></tr>\n");  
  126.         if (dir == 0) {  
  127.             fprintf(client_sock,  
  128.                     "</table><font color=\"CC0000\" size=+2>%s</font></body></html>",  
  129.                     strerror(errno));  
  130.             return;  
  131.         }  
  132.          
  133.         while ((dirent = readdir(dir)) != 0) {  
  134.             if (strcmp(Path, "/") == 0)  
  135.                 sprintf(Filename, "/%s", dirent->d_name);  
  136.             else  
  137.                 sprintf(Filename, "%s/%s", Path, dirent->d_name);  
  138.             fprintf(client_sock, "<tr>");  
  139.             len = strlen(dirroot) + strlen(Filename) + 1;  
  140.             realFilename = malloc(len + 1);  
  141.             bzero(realFilename, len + 1);  
  142.             sprintf(realFilename, "%s/%s", dirroot, Filename);  
  143.             if (stat(realFilename, &info) == 0) {  
  144.                 if (strcmp(dirent->d_name, "..") == 0)  
  145.                     fprintf(client_sock,  
  146.                             "<td><a href=\"http://%s%s%s\">(parent)</a></td>",  
  147.                             host, atoi(port) == 80 ? "" : nport,  
  148.                             dir_up(Path));  
  149.                 else  
  150.                     fprintf(client_sock,  
  151.                             "<td><a href=\"http://%s%s%s\">%s</a></td>",  
  152.                             host, atoi(port) == 80 ? "" : nport, Filename,  
  153.                             dirent->d_name);  
  154.                if (S_ISDIR(info.st_mode))  
  155.                     fprintf(client_sock, "<td>目录</td>");  
  156.                 else if (S_ISREG(info.st_mode))  
  157.                     fprintf(client_sock, "<td>%d</td>", info.st_size);  
  158.                 else if (S_ISLNK(info.st_mode))  
  159.                     fprintf(client_sock, "<td>链接</td>");  
  160.                 else if (S_ISCHR(info.st_mode))  
  161.                     fprintf(client_sock, "<td>字符设备</td>");  
  162.                 else if (S_ISBLK(info.st_mode))  
  163.                     fprintf(client_sock, "<td>块设备</td>");  
  164.                 else if (S_ISFIFO(info.st_mode))  
  165.                     fprintf(client_sock, "<td>FIFO</td>");  
  166.                 else if (S_ISSOCK(info.st_mode))  
  167.                     fprintf(client_sock, "<td>Socket</td>");  
  168.                 else  
  169.                     fprintf(client_sock, "<td>(未知)</td>");  
  170.                 fprintf(client_sock, "<td>%s</td>", ctime(&info.st_ctime));  
  171.             }  
  172.             fprintf(client_sock, "</tr>\n");  
  173.             free(realFilename);  
  174.         }  
  175.         fprintf(client_sock, "</table></center></body></html>");  
  176.     } else {  
  177.          
  178.         fprintf(client_sock,  
  179.                 "HTTP/1.1 200 OK\r\nServer: DAS by ZhouLifa\r\nConnection: close\r\n\r\n<html><head><title>permission denied</title></head>"  
  180.                 "<body><font size=+4>Linux 下目录访问服务器</font><br><hr width=\"100%%\"><br><center>"  
  181.                 "<table border cols=3 width=\"100%%\">");  
  182.         fprintf(client_sock,  
  183.                 "</table><font color=\"CC0000\" size=+2>你访问的资源'%s'被禁止访问,请联系管理员解决!</font></body></html>",  
  184.                 Path);  
  185.     }  
  186.   out:  
  187.     free(realPath);  
  188.     free(nport);  
  189. }  
  190.   
  191. void getoption(int argc, char **argv)  
  192. {  
  193.     int c, len;  
  194.     char *p = 0;  
  195.   
  196.     opterr = 0;  
  197.     while (1) {  
  198.         int option_index = 0;  
  199.   
  200.   static struct option long_options[] = {  
  201.             {"host", 1, 0, 'H'},  
  202.             {"port", 1, 0, 'P'},  
  203.             {"back", 1, 0, 'B'},  
  204.             {"dir", 1, 0, 'D'},  
  205.             {"log", 1, 0, 'L'},  
  206.             {"daemon", 0, 0, 0},  
  207.             {0, 0, 0, 0}  
  208.         };  
  209.     
  210.   
  211.     c = getopt_long(argc, argv, "H:P:B:D:L",  
  212.                         long_options, &option_index);  
  213.         if (c == -1 || c == '?')  
  214.             break;  
  215.   
  216.         if(optarg)        len = strlen(optarg);  
  217.         else        len = 0;  
  218.   
  219.         if ((!c && !(strcasecmp(long_options[option_index].name, "host")))  
  220.             || c == 'H')  
  221.             p = host = malloc(len + 1);  
  222.         else if ((!c  
  223.                   &&  
  224.                   !(strcasecmp(long_options[option_index].name, "port")))  
  225.                  || c == 'P')  
  226.             p = port = malloc(len + 1);  
  227.         else if ((!c  
  228.                   &&  
  229.                   !(strcasecmp(long_options[option_index].name, "back")))  
  230.                  || c == 'B')  
  231.             p = back = malloc(len + 1);  
  232.         else if ((!c  
  233.                   && !(strcasecmp(long_options[option_index].name, "dir")))  
  234.                  || c == 'D')  
  235.             p = dirroot = malloc(len + 1);  
  236.         else if ((!c  
  237.                   && !(strcasecmp(long_options[option_index].name, "log")))  
  238.                  || c == 'L')  
  239.             p = logdir = malloc(len + 1);  
  240.         else if ((!c  
  241.                   &&  
  242.                   !(strcasecmp  
  243.                     (long_options[option_index].name, "daemon")))) {  
  244.             daemon_y_n = 1;  
  245.             continue;  
  246.         }  
  247.         else  
  248.             break;  
  249.         bzero(p, len + 1);  
  250.         memcpy(p, optarg, len);  
  251.     }  
  252. }  
  253.   
  254. int main(int argc, char **argv)  
  255. {  
  256.     struct sockaddr_in addr;  
  257.     int sock_fd, addrlen;  
  258.    
  259.     getoption(argc, argv);  
  260.   
  261.     if (!host) {  
  262.         addrlen = strlen(DEFAULTIP);  
  263.         AllocateMemory(&host, addrlen, DEFAULTIP);  
  264.     }  
  265.     if (!port) {  
  266.         addrlen = strlen(DEFAULTPORT);  
  267.         AllocateMemory(&port, addrlen, DEFAULTPORT);  
  268.     }  
  269.     if (!back) {  
  270.         addrlen = strlen(DEFAULTBACK);  
  271.         AllocateMemory(&back, addrlen, DEFAULTBACK);  
  272.     }  
  273.     if (!dirroot) {  
  274.         addrlen = strlen(DEFAULTDIR);  
  275.         AllocateMemory(&dirroot, addrlen, DEFAULTDIR);  
  276.     }  
  277.     if (!logdir) {  
  278.         addrlen = strlen(DEFAULTLOG);  
  279.         AllocateMemory(&logdir, addrlen, DEFAULTLOG);  
  280.     }  
  281.   
  282.     printf  
  283.         ("host=%s port=%s back=%s dirroot=%s logdir=%s %s  backgroud mode(process ID:%d)\n",  
  284.          host, port, back, dirroot, logdir, daemon_y_n?"":"not", getpid());  
  285.     
  286.   
  287.     if (daemon_y_n) {  
  288.         if (fork())  
  289.             exit(0);  
  290.         if (fork())  
  291.             exit(0);  
  292.         close(0), close(1), close(2);  
  293.         logfp = fopen(logdir, "a+");  
  294.         if (!logfp)  
  295.             exit(0);  
  296.     }  
  297.     
  298.     signal(SIGCHLD, SIG_IGN);  
  299.    
  300.     if ((sock_fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {  
  301.         if (!daemon_y_n) {  
  302.             prterrmsg("socket()");  
  303.         } else {  
  304.             wrterrmsg("socket()");  
  305.         }  
  306.     }  
  307.    
  308.     addrlen = 1;  
  309.     setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &addrlen,  
  310.                sizeof(addrlen));  
  311.   
  312.     addr.sin_family = AF_INET;  
  313.     addr.sin_port = htons(atoi(port));  
  314.     addr.sin_addr.s_addr = inet_addr(host);  
  315.     addrlen = sizeof(struct sockaddr_in);  
  316.    
  317.     if (bind(sock_fd, (struct sockaddr *) &addr, addrlen) < 0) {  
  318.         if (!daemon_y_n) {  
  319.             prterrmsg("bind()");  
  320.         } else {  
  321.             wrterrmsg("bind()");  
  322.         }  
  323.     }  
  324.    
  325.     if (listen(sock_fd, atoi(back)) < 0) {  
  326.         if (!daemon_y_n) {  
  327.             prterrmsg("listen()");  
  328.         } else {  
  329.             wrterrmsg("listen()");  
  330.         }  
  331.     }  
  332.     while (1) {  
  333.         int len;  
  334.         int new_fd;  
  335.         addrlen = sizeof(struct sockaddr_in);  
  336.     
  337.         new_fd = accept(sock_fd, (struct sockaddr *) &addr, &addrlen);  
  338.         if (new_fd < 0) {  
  339.             if (!daemon_y_n) {  
  340.                 prterrmsg("accept()");  
  341.             } else {  
  342.                 wrterrmsg("accept()");  
  343.             }  
  344.             break;  
  345.         }  
  346.         bzero(buffer, MAXBUF + 1);  
  347.         sprintf(buffer, "Connection comes from:\n %s:%d\n",  
  348.                 inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));  
  349.         if (!daemon_y_n) {  
  350.             prtinfomsg(buffer);  
  351.         } else {  
  352.             wrtinfomsg(buffer);  
  353.         }  
  354.     
  355.         if (!fork()) {  
  356.             bzero(buffer, MAXBUF + 1);  
  357.             if ((len = recv(new_fd, buffer, MAXBUF, 0)) > 0) {  
  358.                 FILE *ClientFP = fdopen(new_fd, "w");  
  359.                 if (ClientFP == NULL) {  
  360.                     if (!daemon_y_n) {  
  361.                         prterrmsg("fdopen()");  
  362.                     } else {  
  363.                         prterrmsg("fdopen()");  
  364.                     }  
  365.                 } else {  
  366.                     char Req[MAXPATH + 1] = "";  
  367.                     sscanf(buffer, "GET %s HTTP", Req);  //取buffer内容到Req中(以字符串的形式)  
  368.                     bzero(buffer, MAXBUF + 1);  
  369.                     sprintf(buffer, "Request acquire files: \"%s\"\n", Req);//以字符串的形式将Req的内容传到buffer中  
  370.                     if (!daemon_y_n) {  
  371.                         prtinfomsg(buffer);  
  372.                     } else {  
  373.                         wrtinfomsg(buffer);  
  374.                     }  
  375.                   
  376.                     GiveResponse(ClientFP, Req);  
  377.                     fclose(ClientFP);  
  378.                 }  
  379.             }  
  380.             exit(0);  
  381.         }  
  382.         close(new_fd);  
  383.     }  
  384.     close(sock_fd);  
  385.     return 0;  
  386. }