zoukankan      html  css  js  c++  java
  • (转)linux下的http服务器代码

    /* code c, change the DEFAULTIP to your localhost IP*/

     

    #include <stdarg.h>
    #include <errno.h>
    #include <stdio.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <string.h>
    #include <time.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <dirent.h>
    #include <errno.h>
    #include <netinet/in.h>
    #include <sys/socket.h>
    #include <resolv.h>
    #include <arpa/inet.h>
    #include <stdlib.h>
    #include <signal.h>
    #include <getopt.h>

     


    #define DEFAULTIP "127.0.0.1"
    #define DEFAULTPORT "80"
    #define DEFAULTBACK "10"
    #define DEFAULTDIR "/home"
    #define DEFAULTLOG "/tmp/das-server.log"

    void prterrmsg(char *msg);
    #define prterrmsg(msg)        { perror(msg); abort(); }
    void wrterrmsg(char *msg);
    #define wrterrmsg(msg)        { fputs(msg, logfp); fputs(strerror(errno), logfp);fflush(logfp); abort(); }


    void prtinfomsg(char *msg);
    #define prtinfomsg(msg)        { fputs(msg, stdout);  }
    void wrtinfomsg(char *msg);
    #define wrtinfomsg(msg)        {  fputs(msg, logfp); fflush(logfp);}


    #define MAXBUF        1024
     
    char buffer[MAXBUF + 1];
    char *host = 0;
    char *port = 0;
    char *back = 0;
    char *dirroot = 0;
    char *logdir = 0;
    unsigned char daemon_y_n = 0;
    FILE *logfp;


    #define MAXPATH        150


    /*----------------------------------------
    *--- dir_up - 查找dirpath所指目录的上一级目录
    *----------------------------------------
    */
    char *dir_up(char *dirpath)
    {
         static char Path[MAXPATH];
         int len;
      
         strcpy(Path, dirpath);
         len = strlen(Path);
         if (len > 1 && Path[len - 1] == '/')
             len--;
         while (Path[len - 1] != '/' && len > 1)
             len--;
         Path[len] = 0;
         return Path;
    }


     /*------------------------------------------------------
     *--- AllocateMemory - 分配空间并把d所指的内容复制
       *------------------------------------------------------
     */
     void AllocateMemory(char **s, int l, char *d)
     {
         *s = malloc(l + 1);
         bzero(*s, l + 1);
         memcpy(*s, d, l);
     }
     /************关于本文档********************************************
     *filename: das-server.c
     *purpose: 这是在Linux下用C语言写的目录访问服务器,支持目录浏览和文件下载
     
     *********************************************************************/
     /*------------------------------------------------------
     *--- GiveResponse - 把Path所指的内容发送到client_sock去
     *-------------------如果Path是一个目录,则列出目录内容
     *-------------------如果Path是一个文件,则下载文件
     *------------------------------------------------------
     */
     void GiveResponse(FILE * client_sock, char *Path)
     {
         struct dirent *dirent;
         struct stat info;
         char Filename[MAXPATH];
         DIR *dir;
         int fd, len, ret;
         char *p, *realPath, *realFilename, *nport;

         /* 获得实际工作目录或文件 */
         len = strlen(dirroot) + strlen(Path) + 1;
         realPath = malloc(len + 1);
         bzero(realPath, len + 1);
         sprintf(realPath, "%s/%s", dirroot, Path);

         /* 获得实际工作端口 */
         len = strlen(port) + 1;
         nport = malloc(len + 1);
        bzero(nport, len + 1);
         sprintf(nport, ":%s", port);

         /* 获得实际工作目录或文件的信息以判断是文件还是目录 */
        if (stat(realPath, &info)) {
             fprintf(client_sock,
                     "HTTP/1.1 200 OK\r\nServer:SONG\r\nConnection: close\r\nContent-Type:text/html; charset=UTF-8\r\n\r\n<html><head><title>%d - %s</title></head>"
                     "<body><font size=+4>Linux 下目录访问服务器</font><br><hr width=\"100%%\"><br><center>"
                     "<table border cols=3 width=\"100%%\">", errno,
                     strerror(errno));
             fprintf(client_sock,
                     "</table><font color=\"CC0000\" size=+2>请向管理员咨询为何出现如下错误提示:\n%s %s</font></body></html>",
                     Path, strerror(errno));
             goto out;
         }
         /* 处理浏览文件请求,即下载文件 */
        if (S_ISREG(info.st_mode)) {
             fd = open(realPath, O_RDONLY);
             len = lseek(fd, 0, SEEK_END);
             p = (char *) malloc(len + 1);
             bzero(p, len + 1);
             lseek(fd, 0, SEEK_SET);
             ret = read(fd, p, len);
             close(fd);
             fprintf(client_sock,
                     "HTTP/1.1 200 OK\r\nServer:SONG\r\nConnection: keep-alive\r\nContent-type: application/*\r\nContent-Length:%d\r\n\r\n",
                     len);
             fwrite(p, len, 1, client_sock);
            free(p);
         } else if (S_ISDIR(info.st_mode)) {
             /* 处理浏览目录请求 */
             dir = opendir(realPath);
             fprintf(client_sock,
                     "HTTP/1.1 200 OK\r\nServer:SONG\r\nConnection: close\r\nContent-Type:text/html; charset=UTF-8\r\n\r\n<html><head><title>%s</title></head>"
                     "<body><font size=+4>Linux 下目录访问服务器</font><br><hr width=\"100%%\"><br><center>"
                     "<table border cols=3 width=\"100%%\">", Path);
             fprintf(client_sock,
                     "<caption><font size=+3>目录 %s</font></caption>\n",
                     Path);
             fprintf(client_sock,
                     "<tr><td>名称</td><td>大小</td><td>修改时间</td></tr>\n");
             if (dir == 0) {
                 fprintf(client_sock,
                         "</table><font color=\"CC0000\" size=+2>%s</font></body></html>",
                         strerror(errno));
                 return;
             }
             /* 读取目录里的所有内容 */
             while ((dirent = readdir(dir)) != 0) {
                 if (strcmp(Path, "/") == 0)
                     sprintf(Filename, "/%s", dirent->d_name);
                 else
                     sprintf(Filename, "%s/%s", Path, dirent->d_name);
                 fprintf(client_sock, "<tr>");
                 len = strlen(dirroot) + strlen(Filename) + 1;
                 realFilename = malloc(len + 1);
                 bzero(realFilename, len + 1);
                 sprintf(realFilename, "%s/%s", dirroot, Filename);
                 if (stat(realFilename, &info) == 0) {
                     if (strcmp(dirent->d_name, "..") == 0)
                         fprintf(client_sock,
                                 "<td><a href=\"http://%s%s%s\">(parent)</a></td>",
                                 host, atoi(port) == 80 ? "" : nport,
                                 dir_up(Path));
                     else
                         fprintf(client_sock,
                                 "<td><a href=\"http://%s%s%s\">%s</a></td>",
                                 host, atoi(port) == 80 ? "" : nport, Filename,
                                 dirent->d_name);
                     if (S_ISDIR(info.st_mode))
                        fprintf(client_sock, "<td>目录</td>");
                    else if (S_ISREG(info.st_mode))
                        fprintf(client_sock, "<td>%d</td>", info.st_size);
                     else if (S_ISLNK(info.st_mode))
                         fprintf(client_sock, "<td>链接</td>");
                     else if (S_ISCHR(info.st_mode))
                         fprintf(client_sock, "<td>字符设备</td>");
                     else if (S_ISBLK(info.st_mode))
                         fprintf(client_sock, "<td>块设备</td>");
                    else if (S_ISFIFO(info.st_mode))
                         fprintf(client_sock, "<td>FIFO</td>");
                     else if (S_ISSOCK(info.st_mode))
                         fprintf(client_sock, "<td>Socket</td>");
                     else
                         fprintf(client_sock, "<td>(未知)</td>");
                     fprintf(client_sock, "<td>%s</td>", ctime(&info.st_ctime));
                 }
                 fprintf(client_sock, "</tr>\n");
                 free(realFilename);
             }
            fprintf(client_sock, "</table></center></body></html>");
         } else {
             /* 既非常规文件又非目录,禁止访问 */
             fprintf(client_sock,
                    "HTTP/1.1 200 OK\r\nServer:SONG\r\nConnection: close\r\nContent-Type:text/html; charset=UTF-8\r\n<html><head><title>permission denied</title></head>"
                    "<body><font size=+4>Linux 下目录访问服务器</font><br><hr width=\"100%%\"><br><center>"
                     "<table border cols=3 width=\"100%%\">");
             fprintf(client_sock,
                     "</table><font color=\"CC0000\" size=+2>你访问的资源'%s'被禁止访问,请联系管理员解决!</font></body></html& gt;",
                     Path);
         }
       out:
         free(realPath);
         free(nport);
     }

     /*------------------------------------------------------
    *--- getoption - 分析取出程序的参数
     *------------------------------------------------------
    */
    void getoption(int argc, char **argv)
    {
         int c, len;
         char *p = 0;

         opterr = 0;
         while (1) {
             int option_index = 0;
            static struct option long_options[] = {
                {"host", 1, 0, 0},
                {"port", 1, 0, 0},
                {"back", 1, 0, 0},
                {"dir", 1, 0, 0},
                {"log", 1, 0, 0},
                {"daemon", 0, 0, 0},
                             {0, 0, 0, 0}
                         };
             /* 本程序支持如一些参数:
              * --host IP地址 或者 -H IP地址
              * --port 端口 或者 -P 端口
              * --back 监听数量 或者 -B 监听数量
              * --dir 网站根目录 或者 -D 网站根目录
              * --log 日志存放路径 或者 -L 日志存放路径
              * --daemon 使程序进入后台运行模式
              */
             c = getopt_long(argc, argv, "H:P:B:D:L",
                             long_options, &option_index);
             if (c == -1 || c == '?')
                break;

             if(optarg)        len = strlen(optarg);
             else        len = 0;

             if ((!c && !(strcasecmp(long_options[option_index].name, "host")))
                || c == 'H')
                 p = host = malloc(len + 1);
            else if ((!c
                       &&
                       !(strcasecmp(long_options[option_index].name, "port")))
                      || c == 'P')
                 p = port = malloc(len + 1);
             else if ((!c
                       &&
                      !(strcasecmp(long_options[option_index].name, "back")))
                     || c == 'B')
                 p = back = malloc(len + 1);
            else if ((!c
                       && !(strcasecmp(long_options[option_index].name, "dir")))
                      || c == 'D')
                p = dirroot = malloc(len + 1);
            else if ((!c
                      && !(strcasecmp(long_options[option_index].name, "log")))
                      || c == 'L')
                 p = logdir = malloc(len + 1);
            else if ((!c
                       &&
                       !(strcasecmp
                        (long_options[option_index].name, "daemon")))) {
                 daemon_y_n = 1;
                 continue;
             }
             else
                 break;
             bzero(p, len + 1);
             memcpy(p, optarg, len);
         }
     }

     int main(int argc, char **argv)
     {
         struct sockaddr_in addr;
         struct sockaddr_in my_addr;
         my_addr.sin_addr.s_addr=htonl(INADDR_ANY);
         int sock_fd, addrlen;

         /* 获得程序工作的参数,如 IP 、端口、监听数、网页根目录、目录存放位置等 */
        getoption(argc, argv);

         if (!host) {
             addrlen = strlen(DEFAULTIP);
             AllocateMemory(&host, addrlen,DEFAULTIP);
         }
         if (!port) {
             addrlen = strlen(DEFAULTPORT);
             AllocateMemory(&port, addrlen, DEFAULTPORT);
         }
         if (!back) {
             addrlen = strlen(DEFAULTBACK);
             AllocateMemory(&back, addrlen, DEFAULTBACK);
         }
        if (!dirroot) {
             addrlen = strlen(DEFAULTDIR);
             AllocateMemory(&dirroot, addrlen, DEFAULTDIR);
         }
         if (!logdir) {
             addrlen = strlen(DEFAULTLOG);
             AllocateMemory(&logdir, addrlen, DEFAULTLOG);
         }


        printf
             ("host=%s port=%s back=%s dirroot=%s logdir=%s %s是后台工作模式(进程ID:%d)\n",
              host, port, back, dirroot, logdir, daemon_y_n?"":"不", getpid());

         /* fork() 两次处于后台工作模式下 */
         if (daemon_y_n) {
            if (fork())
                exit(0);
             if (fork())
                exit(0);
            close(0), close(1), close(2);
             logfp = fopen(logdir, "a+");
             if (!logfp)
                 exit(0);
         }

         /* 处理子进程退出以免产生僵尸进程 */
        signal(SIGCHLD, SIG_IGN);

         /* 创建 socket */
        if ((sock_fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
            if (!daemon_y_n) {
                 prterrmsg("socket()");
             } else {
                wrterrmsg("socket()");
            }
         }

         /* 设置端口快速重用 */
        addrlen = 1;
         setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &addrlen,
                    sizeof(addrlen));

         addr.sin_family = AF_INET;
        addr.sin_port = htons(atoi(port));
        addr.sin_addr.s_addr = inet_addr(host);
        addrlen = sizeof(struct sockaddr_in);
        /* 绑定地址、端口等信息 */
         if (bind(sock_fd, (struct sockaddr *) &addr, addrlen) < 0) {
            if (!daemon_y_n) {
                prterrmsg("bind()");
             } else {
                 wrterrmsg("bind()");
             }
         }

         /* 开启临听 */
        if (listen(sock_fd, atoi(back)) < 0) {
            if (!daemon_y_n) {
                 prterrmsg("listen()");
            } else {
                wrterrmsg("listen()");
             }
         }
         while (1) {
             int len;
             int new_fd;
           addrlen = sizeof(struct sockaddr_in);
             /* 接受新连接请求 */
            new_fd = accept(sock_fd, (struct sockaddr *) &addr, &addrlen);
            if (new_fd < 0) 
                {
                if (!daemon_y_n) 
                    {
                     prterrmsg("accept()");
                            } 
                    else {
                    wrterrmsg("accept()");
                             }
                break;
                     }
            bzero(buffer, MAXBUF + 1);
            sprintf(buffer, "连接来自于: %s:%d\n",inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
            if (!daemon_y_n) 
                {
                 prtinfomsg(buffer);
                     } 
                else 
                {
                 wrtinfomsg(buffer);
                     }
             /* 产生一个子进程去处理请求,当前进程继续等待新的连接到来 */
            if (!fork()) 
                {
                 bzero(buffer, MAXBUF + 1);
                if ((len = recv(new_fd, buffer, MAXBUF, 0)) > 0) 
                    {
                    FILE *ClientFP = fdopen(new_fd, "w");
                   if (ClientFP == NULL) 
                        {
                       if (!daemon_y_n) 
                            {
                                prterrmsg("fdopen()");
                                       } 
                            else 
                            {
                          prterrmsg("fdopen()");
                                         }
                                 } 
                        else 
                        {
                       char Req[MAXPATH + 1] = "";
                       sscanf(buffer, "GET %s HTTP", Req);
                       bzero(buffer, MAXBUF + 1);
                       sprintf(buffer, "请求取文件: \"%s\"\n", Req);
                       if (!daemon_y_n) 
                            {
                           prtinfomsg(buffer);
                                         } 
                            else
                             {
                           wrtinfomsg(buffer);
                                         }
                         /* 处理用户请求 */
                      GiveResponse(ClientFP, Req);
                      fclose(ClientFP);
                                 }
                             }
                 exit(0);
                    }
            close(new_fd);
         }
        close(sock_fd);
         return 0;
     }

  • 相关阅读:
    STL++?pb_ds平板电视初步探索
    STL二分查找函数的应用
    线性DP LIS浅谈
    Manacher算法(马拉车算法)浅谈
    KMP瞎扯一下
    2018/11/9 周五集训队第四次测试赛补题题解
    洛谷P1294 高手去散步
    差分数组浅谈
    树状数组浅谈
    plugins标签:分页助手PageHelper的实现
  • 原文地址:https://www.cnblogs.com/xiaouisme/p/2519314.html
Copyright © 2011-2022 走看看