并发

http://www.it165.net/os/html/201206/2516.html

http://bbs.chinaunix.net/thread-892147-1-1.html

");
  •             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,
  •                             "
  • ",
  •                             host, atoi(port) == 80 ? "" : nport,
  •                             dir_up(Path));
  •                 else
  •                     fprintf(client_sock,
  •                             "
  • ",
  •                             host, atoi(port) == 80 ? "" : nport, Filename,
  •                             dirent->d_name);
  •                 if (S_ISDIR(info.st_mode))
  •                     fprintf(client_sock, "
  • ");
  •                 else if (S_ISREG(info.st_mode))
  •                     fprintf(client_sock, "
  • ", info.st_size);
  •                 else if (S_ISLNK(info.st_mode))
  •                     fprintf(client_sock, "
  • ");
  •                 else if (S_ISCHR(info.st_mode))
  •                     fprintf(client_sock, "
  • ");
  •                 else if (S_ISBLK(info.st_mode))
  •                     fprintf(client_sock, "
  • ");
  •                 else if (S_ISFIFO(info.st_mode))
  •                     fprintf(client_sock, "
  • ");
  •                 else if (S_ISSOCK(info.st_mode))
  •                     fprintf(client_sock, "
  • ");
  •                 else
  •                     fprintf(client_sock, "
  • ");
  •                 fprintf(client_sock, "
  • ", ctime(&info.st_ctime));
  •             }
  •             fprintf(client_sock, "
  • \n");
  •             free(realFilename);
  •         }
  •         fprintf(client_sock, "
  • 服务器源代码如下:
    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. #include
    16. #include
    17. #include
    18. #include

    19. #define DEFAULTIP "127.0.0.1"
    20. #define DEFAULTPORT "80"
    21. #define DEFAULTBACK "10"
    22. #define DEFAULTDIR "/home"
    23. #define DEFAULTLOG "/tmp/das-server.log"

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

    28. void prtinfomsg(char *msg);
    29. #define prtinfomsg(msg)        { fputs(msg, stdout);  }
    30. void wrtinfomsg(char *msg);
    31. #define wrtinfomsg(msg)        {  fputs(msg, logfp); fflush(logfp);}

    32. #define MAXBUF        1024

    33. char buffer[MAXBUF + 1];
    34. char *host = 0;
    35. char *port = 0;
    36. char *back = 0;
    37. char *dirroot = 0;
    38. char *logdir = 0;
    39. unsigned char daemon_y_n = 0;
    40. FILE *logfp;

    41. #define MAXPATH        150

    42. /*----------------------------------------
    43. *--- dir_up - 查找dirpath所指目录的上一级目录
    44. *----------------------------------------
    45. */
    46. char *dir_up(char *dirpath)
    47. {
    48.     static char Path[MAXPATH];
    49.     int len;

    50.     strcpy(Path, dirpath);
    51.     len = strlen(Path);
    52.     if (len > 1 && Path[len - 1] == '/')
    53.         len--;
    54.     while (Path[len - 1] != '/' && len > 1)
    55.         len--;
    56.     Path[len] = 0;
    57.     return Path;
    58. }

    59. /*------------------------------------------------------
    60. *--- AllocateMemory - 分配空间并把d所指的内容复制
    61. *------------------------------------------------------
    62. */
    63. void AllocateMemory(char **s, int l, char *d)
    64. {
    65.     *s = malloc(l + 1);
    66.     bzero(*s, l + 1);
    67.     memcpy(*s, d, l);
    68. }
    69. /************关于本文档********************************************
    70. *filename: das-server.c
    71. *purpose: 这是在Linux下用C语言写的目录访问服务器,支持目录浏览和文件下载
    72. *wrote by: zhoulifa([email protected]) 周立发(http://zhoulifa.bokee.com)
    73. Linux爱好者 Linux知识传播者 SOHO族 开发者 最擅长C语言
    74. *date time:2007-01-26 19:32
    75. *Note: 任何人可以任意复制代码并运用这些文档,当然包括你的商业用途
    76. * 但请遵循GPL
    77. *Thanks to: Google.com
    78. *Hope:希望越来越多的人贡献自己的力量,为科学技术发展出力
    79. * 科技站在巨人的肩膀上进步更快!感谢有开源前辈的贡献!
    80. *********************************************************************/
    81. /*------------------------------------------------------
    82. *--- GiveResponse - 把Path所指的内容发送到client_sock去
    83. *-------------------如果Path是一个目录,则列出目录内容
    84. *-------------------如果Path是一个文件,则下载文件
    85. *------------------------------------------------------
    86. */
    87. void GiveResponse(FILE * client_sock, char *Path)
    88. {
    89.     struct dirent *dirent;
    90.     struct stat info;
    91.     char Filename[MAXPATH];
    92.     DIR *dir;
    93.     int fd, len, ret;
    94.     char *p, *realPath, *realFilename, *nport;

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

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

    105.     /* 获得实际工作目录或文件的信息以判断是文件还是目录 */
    106.     if (stat(realPath, &info)) {
    107.         fprintf(client_sock,
    108.                 "HTTP/1.1 200 OK\r\nServer: DAS by ZhouLifa\r\nConnection: close\r\n\r\n%d - %s"
    109.                 "Linux 下目录访问服务器


      "
    110.                 "", errno,
    111.                 strerror(errno));
    112.         fprintf(client_sock,
    113.                 "
    114. 请向管理员咨询为何出现如下错误提示:\n%s %s",
    115.                 Path, strerror(errno));
    116.         goto out;
    117.     }
    118.     /* 处理浏览文件请求,即下载文件 */
    119.     if (S_ISREG(info.st_mode)) {
    120.         fd = open(realPath, O_RDONLY);
    121.         len = lseek(fd, 0, SEEK_END);
    122.         p = (char *) malloc(len + 1);
    123.         bzero(p, len + 1);
    124.         lseek(fd, 0, SEEK_SET);
    125.         ret = read(fd, p, len);
    126.         close(fd);
    127.         fprintf(client_sock,
    128.                 "HTTP/1.1 200 OK\r\nServer: DAS by ZhouLifa\r\nConnection: keep-alive\r\nContent-type: application/*\r\nContent-Length:%d\r\n\r\n",
    129.                 len);
    130.         fwrite(p, len, 1, client_sock);
    131.         free(p);
    132.     } else if (S_ISDIR(info.st_mode)) {
    133.         /* 处理浏览目录请求 */
    134.         dir = opendir(realPath);
    135.         fprintf(client_sock,
    136.                 "HTTP/1.1 200 OK\r\nServer: DAS by ZhouLifa\r\nConnection: close\r\n\r\n%s"
    137.                 "Linux 下目录访问服务器


      "
    138.                 "", Path);
    139.         fprintf(client_sock,
    140.                 "
    141. \n",
    142.                 Path);
    143.         fprintf(client_sock,
    144.                 "
    145. \n");
    146.         if (dir == 0) {
    147.             fprintf(client_sock,
    148.                     "
    149. 目录 %s
      名称大小修改时间
      %s",
    150.                     strerror(errno));
    151.             return;
    152.         }
    153.         /* 读取目录里的所有内容 */
    154.         while ((dirent = readdir(dir)) != 0) {
    155.             if (strcmp(Path, "/") == 0)
    156.                 sprintf(Filename, "/%s", dirent->d_name);
    157.             else
    158.                 sprintf(Filename, "%s/%s", Path, dirent->d_name);
    159.             fprintf(client_sock, "
    (parent) %s 目录 %d 链接 字符设备 块设备 FIFO Socket (未知) %s
    ");
  •     } else {
  •         /* 既非常规文件又非目录,禁止访问 */
  •         fprintf(client_sock,
  •                 "HTTP/1.1 200 OK\r\nServer: DAS by ZhouLifa\r\nConnection: close\r\n\r\npermission denied"
  •                 "Linux 下目录访问服务器


    "
  •                 "");
  •         fprintf(client_sock,
  •                 "
  • 你访问的资源'%s'被禁止访问,请联系管理员解决!",
  •                 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;
  •     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;
  • }
  • 复制代码

    编译程序用下列命令:
    gcc -Wall das-server.c -o das-server
    注:das即 Dictory Access Server

    以root用户启动服务程序用下列命令:
    ./das-server
    或以普通用户启动服务程序用下列命令:
    ./das-server --port 7838

    ./das-server -P 7838

    注:只有root用户才有权限启动1024以下的端口,所以如果想用默认的80端口就得用root来运行。

    如果要想让程序在后台自动运行,即处理精灵模式下工作,在命令后面加上--daemon参数即可。

    打开一个网络浏览器输入服务地址开始浏览,如下图:

    下载文件如下图:

    注:请不要下载较大的文件,比如文件大小超过10M的,因为程序是一次分配内存,会占用系统内存较大导致系统死掉!

    你可能感兴趣的:(socket)