Chinaunix

标题: 一个web服务器的实现 [打印本页]

作者: liuke432    时间: 2006-06-21 15:52
标题: 一个web服务器的实现
题目:  一个web服务器的实现

客户端(浏览器)与web服务器之间的交互主要包含客户的请求和服务器的应答。
请求和应答的格式在超文本传输协议(HTTP)中有定义。HTTP协议使用纯文本。

例如:
$telnet  www.ouc.edu.cn  80
Trying 211.64.150.68...
Connected to www.ouc.edu.cn(211.64.150.6
Escape character is '^]'.
GET /index.html HTTP/1.0

HTTP/1.1  200  OK
Date: Wed, 21 Jun 2006  08:26:04 GMT
Server: Apache/2.0.54(Unix) DAV/2
..................................

原理是telnet创建了一个socket并调用了connect来连接到web服务器。服务器
接受连接请求,并创建了一个基于socket的从客户端的键盘到web服务进程的数据通道。接下来,客户端输入请求:
GET /index.html HTTP/1.0

一个HTTP请求包含有3个字符串。第一个字符串是命令,第二个是参数,第三个是所用协议的版本号。  *注意还有一空行

web服务器读取请求,检查请求,然后返回一个请求。应答有两部分:头部和内容。头部以状态行起始,如下所示:

HTTP/1.1  200  ok

状态行含有两个或更多的字符串。第一个串是协议的版本,第二个串是返回码,这里是200,其文本解释是OK。头部的其余部分是关于应答的附加信息。
应答的其余部分是返回的具体内容。


下面这个webserv.c就是一个web服务器的具体实现。

编译程序,在某个端口运行它:
$gcc webserv.c  -o  webserv
$./webserv  12345
就可以访问web服务器,网址为http://yourhostname:12345/  
将html文件放到该目录中并且用http://yourhostname:12345//filename.html就可以访问。



  1. /* webserv.c - a web server
  2. *      build: gcc webserv.c -o webserv
  3. */
  4. #include        <stdio.h>
  5. #include        <unistd.h>
  6. #include        <sys/types.h>
  7. #include        <sys/socket.h>
  8. #include        <netinet/in.h>
  9. #include        <netdb.h>
  10. #include        <sys/stat.h>
  11. #include        <time.h>
  12. #include        <string.h>

  13. #define   HOSTLEN  256
  14. #define          BACKLOG  1


  15. main(int ac, char *av[])
  16. {
  17.         int         sock, fd;
  18.         FILE        *fpin;
  19.         char        request[BUFSIZ];

  20.         if ( ac == 1 ){
  21.                 fprintf(stderr,"usage: ws portnum\n");
  22.                 exit(1);
  23.         }
  24.         sock = make_server_socket( atoi(av[1]) );
  25.         if ( sock == -1 ) exit(2);

  26.         /* main loop here */

  27.         while(1){
  28.                 /* take a call and buffer it */
  29.                 fd = accept( sock, NULL, NULL );
  30.                 fpin = fdopen(fd, "r" );

  31.                 /* read request */
  32.                 fgets(request,BUFSIZ,fpin);
  33.                 printf("got a call: request = %s", request);
  34.                 read_til_crnl(fpin);

  35.                 /* do what client asks */
  36.                 process_rq(request, fd);

  37.                 fclose(fpin);
  38.         }
  39. }

  40. /* ------------------------------------------------------ *
  41.    make_server_socket(int portnum)
  42.    创建一个服务器套接字,并调用listen监听
  43.    ------------------------------------------------------ */

  44. int make_server_socket(int portnum)
  45. {
  46.         return make_server_socket_q(portnum, BACKLOG);
  47. }
  48. int make_server_socket_q(int portnum, int backlog)
  49. {
  50.         struct  sockaddr_in   saddr;   /* build our address here */
  51.         struct        hostent                *hp;   /* this is part of our    */
  52.         char        hostname[HOSTLEN];     /* address                  */
  53.         int        sock_id;               /* the socket             */

  54.         sock_id = socket(PF_INET, SOCK_STREAM, 0);  /* get a socket */
  55.         if ( sock_id == -1 )
  56.                 return -1;

  57.         /** build address and bind it to socket **/

  58.         bzero((void *)&saddr, sizeof(saddr));   /* clear out struct     */
  59.         gethostname(hostname, HOSTLEN);         /* where am I ?         */
  60.         hp = gethostbyname(hostname);           /* get info about host  */
  61.                                                 /* fill in host part    */
  62.         bcopy( (void *)hp->h_addr, (void *)&saddr.sin_addr, hp->h_length);
  63.         saddr.sin_port = htons(portnum);        /* fill in socket port  */
  64.         saddr.sin_family = AF_INET ;            /* fill in addr family  */
  65.         if ( bind(sock_id, (struct sockaddr *)&saddr, sizeof(saddr)) != 0 )
  66.                return -1;

  67.         /** arrange for incoming calls **/

  68.         if ( listen(sock_id, backlog) != 0 )
  69.                 return -1;
  70.         return sock_id;
  71. }


  72. /* ------------------------------------------------------ *
  73.    read_til_crnl(FILE *)
  74.    skip over all request info until a CRNL is seen
  75.    ------------------------------------------------------ */

  76. read_til_crnl(FILE *fp)
  77. {
  78.         char        buf[BUFSIZ];
  79.         while( fgets(buf,BUFSIZ,fp) != NULL && strcmp(buf,"\r\n") != 0 )
  80.                 ;
  81. }

  82. /* ------------------------------------------------------ *
  83.    process_rq( char *rq, int fd )
  84.    分析客户端的请求,分析然后做出相应的应答
  85.    rq is HTTP command:  GET /foo/bar.html HTTP/1.0
  86.    ------------------------------------------------------ */

  87. process_rq( char *rq, int fd )
  88. {
  89.         char        cmd[BUFSIZ], arg[BUFSIZ];

  90.         /* create a new process and return if not the child */
  91.         if ( fork() != 0 )
  92.                 return;

  93.         strcpy(arg, "./");                /* precede args with ./ */
  94.         if ( sscanf(rq, "%s%s", cmd, arg+2) != 2 )
  95.                 return;

  96.         if ( strcmp(cmd,"GET") != 0 )
  97.                 cannot_do(fd);
  98.         else if ( not_exist( arg ) )
  99.                 do_404(arg, fd );
  100.         else if ( isadir( arg ) )
  101.                 do_ls( arg, fd );
  102.         else if ( ends_in_cgi( arg ) )
  103.                 do_exec( arg, fd );
  104.         else
  105.                 do_cat( arg, fd );
  106. }

  107. /* ------------------------------------------------------ *
  108.    the reply header thing: all functions need one
  109.    if content_type is NULL then don't send content type
  110.    ------------------------------------------------------ */

  111. header( FILE *fp, char *content_type )
  112. {
  113.         fprintf(fp, "HTTP/1.0 200 OK\r\n");
  114.         if ( content_type )
  115.                 fprintf(fp, "Content-type: %s\r\n", content_type );
  116. }

  117. /* ------------------------------------------------------ *
  118.    simple functions first:
  119.         cannot_do(fd)       unimplemented HTTP command
  120.     and do_404(item,fd)     no such object
  121.    ------------------------------------------------------ */

  122. cannot_do(int fd)
  123. {
  124.         FILE        *fp = fdopen(fd,"w");

  125.         fprintf(fp, "HTTP/1.0 501 Not Implemented\r\n");
  126.         fprintf(fp, "Content-type: text/plain\r\n");
  127.         fprintf(fp, "\r\n");

  128.         fprintf(fp, "That command is not yet implemented\r\n");
  129.         fclose(fp);
  130. }

  131. do_404(char *item, int fd)
  132. {
  133.         FILE        *fp = fdopen(fd,"w");

  134.         fprintf(fp, "HTTP/1.0 404 Not Found\r\n");
  135.         fprintf(fp, "Content-type: text/plain\r\n");
  136.         fprintf(fp, "\r\n");

  137.         fprintf(fp, "The item you requested: %s\r\nis not found\r\n",
  138.                         item);
  139.         fclose(fp);
  140. }

  141. /* ------------------------------------------------------ *
  142.    the directory listing section
  143.    isadir() uses stat, not_exist() uses stat
  144.    do_ls runs ls. It should not
  145.    ------------------------------------------------------ */

  146. isadir(char *f)
  147. {
  148.         struct stat info;
  149.         return ( stat(f, &info) != -1 && S_ISDIR(info.st_mode) );
  150. }

  151. not_exist(char *f)
  152. {
  153.         struct stat info;
  154.         return( stat(f,&info) == -1 );
  155. }

  156. do_ls(char *dir, int fd)
  157. {
  158.         FILE        *fp ;

  159.         fp = fdopen(fd,"w");
  160.         header(fp, "text/plain");
  161.         fprintf(fp,"\r\n");
  162.         fflush(fp);

  163.         dup2(fd,1);
  164.         dup2(fd,2);
  165.         close(fd);
  166.         execlp("ls","ls","-l",dir,NULL);
  167.         perror(dir);
  168.         exit(1);
  169. }

  170. /* ------------------------------------------------------ *
  171.    the cgi stuff.  function to check extension and
  172.    one to run the program.
  173.    ------------------------------------------------------ */

  174. char * file_type(char *f)
  175. /* returns 'extension' of file */
  176. {
  177.         char        *cp;
  178.         if ( (cp = strrchr(f, '.' )) != NULL )
  179.                 return cp+1;
  180.         return "";
  181. }

  182. ends_in_cgi(char *f)
  183. {
  184.         return ( strcmp( file_type(f), "cgi" ) == 0 );
  185. }

  186. do_exec( char *prog, int fd )
  187. {
  188.         FILE        *fp ;

  189.         fp = fdopen(fd,"w");
  190.         header(fp, NULL);
  191.         fflush(fp);
  192.         dup2(fd, 1);
  193.         dup2(fd, 2);
  194.         close(fd);
  195.         execl(prog,prog,NULL);
  196.         perror(prog);
  197. }
  198. /* ------------------------------------------------------ *
  199.    do_cat(filename,fd)
  200.    sends back contents after a header
  201.    ------------------------------------------------------ */

  202. do_cat(char *f, int fd)
  203. {
  204.         char        *extension = file_type(f);
  205.         char        *content = "text/plain";
  206.         FILE        *fpsock, *fpfile;
  207.         int        c;

  208.         if ( strcmp(extension,"html") == 0 )
  209.                 content = "text/html";
  210.         else if ( strcmp(extension, "gif") == 0 )
  211.                 content = "image/gif";
  212.         else if ( strcmp(extension, "jpg") == 0 )
  213.                 content = "image/jpeg";
  214.         else if ( strcmp(extension, "jpeg") == 0 )
  215.                 content = "image/jpeg";

  216.         fpsock = fdopen(fd, "w");
  217.         fpfile = fopen( f , "r");
  218.         if ( fpsock != NULL && fpfile != NULL )
  219.         {
  220.                 header( fpsock, content );
  221.                 fprintf(fpsock, "\r\n");
  222.                 while( (c = getc(fpfile) ) != EOF )
  223.                         putc(c, fpsock);
  224.                 fclose(fpfile);
  225.                 fclose(fpsock);
  226.         }
  227.         exit(0);
  228. }
复制代码

[ 本帖最后由 liuke432 于 2006-6-21 16:46 编辑 ]
作者: er    时间: 2006-06-21 15:58
支持
作者: kuaizaifeng    时间: 2006-06-21 16:12
好东东,支持
作者: cmh_2003    时间: 2006-06-21 17:43
先顶下慢慢看~~~
作者: HAMMER    时间: 2006-06-21 17:52
新到任的高手啊
作者: linuxcici    时间: 2006-06-21 18:38
请问WEB服务器写的时候要注意点什么呢? 小弟正在学. ....好象很多书有关于这web server的code.
作者: liuke432    时间: 2006-06-22 09:27
原帖由 HAMMER 于 2006-6-21 17:52 发表
新到任的高手啊

多谢兄弟抬举,我还称不上是什么高手。 :)
学习unix网络编程才半年多,看到有本书上的这个例子比较不错,
对于学习网络编程的朋友很有实践价值。于是就整理了一下,让大
家一起学习。
作者: liuke432    时间: 2006-06-22 09:41
原帖由 linuxcici 于 2006-6-21 18:38 发表
请问WEB服务器写的时候要注意点什么呢? 小弟正在学. ....好象很多书有关于这web server的code.

我对这个还不是很精通。   
web服务器的侧重点不一样,有的提供了更多的安全特征,有的则快速处理请求或使用较少的内存。
其中一个重要的特征是服务器的效率问题。服务器可以同时处理多少个请求?对于每个请求,服务器需要多少系统资源?
上面那个程序是用多进程来处理的。   
下面再贴一个多线程的。
作者: liuke432    时间: 2006-06-22 09:55
多线程的web服务器

多线程版本增加了内部统计功能:
     服务器的运行时间
     接收的客户端请求的数目
     发送回客户端的数据量

这里使用独立线程(Detached Threads)防止僵尸线程(Zombie Threads)


  1. /* webserv_pthread.c - a threaded  web server
  2. * building: gcc webserv_pthread.c -lpthread -o webserv_pthread
  3. */

  4. #include <stdio.h>
  5. #include <sys/types.h>
  6. #include <sys/socket.h>
  7. #include <netinet/in.h>
  8. #include <netdb.h>
  9. #include <sys/stat.h>
  10. #include <string.h>

  11. #include <pthread.h>
  12. #include <stdlib.h>
  13. #include <unistd.h>

  14. #include <dirent.h>
  15. #include <time.h>

  16. #define   HOSTLEN  256
  17. #define          BACKLOG  1

  18. /* server facts here */

  19. time_t         server_started ;
  20. int         server_bytes_sent;
  21. int         server_requests;

  22. main(int ac, char *av[])
  23. {
  24.         int                 sock, fd;
  25.         int                *fdptr;
  26.         pthread_t        worker;
  27.         pthread_attr_t        attr;

  28.         void *handle_call(void *);

  29.         if ( ac == 1 ){
  30.                 fprintf(stderr,"usage: tws portnum\n");
  31.                 exit(1);
  32.         }
  33.         sock = make_server_socket( atoi(av[1]) );
  34.         if ( sock == -1 ) { perror("making socket"); exit(2); }

  35.         setup(&attr);

  36.         /* main loop here: take call, handle call in new thread  */

  37.         while(1){
  38.                 fd = accept( sock, NULL, NULL );
  39.                 server_requests++;

  40.                 fdptr = malloc(sizeof(int));
  41.                 *fdptr = fd;
  42.                 pthread_create(&worker,&attr,handle_call,fdptr);
  43.         }
  44. }


  45. /* ------------------------------------------------------ *
  46.    make_server_socket(int portnum)
  47.    创建一个服务器套接字,并调用listen监听
  48.    ------------------------------------------------------ */

  49. int make_server_socket_q(int , int );

  50. int make_server_socket(int portnum)
  51. {
  52.         return make_server_socket_q(portnum, BACKLOG);
  53. }
  54. int make_server_socket_q(int portnum, int backlog)
  55. {
  56.         struct  sockaddr_in   saddr;   /* build our address here */
  57.         struct        hostent                *hp;   /* this is part of our    */
  58.         char        hostname[HOSTLEN];     /* address                  */
  59.         int        sock_id;               /* the socket             */

  60.         sock_id = socket(PF_INET, SOCK_STREAM, 0);  /* get a socket */
  61.         if ( sock_id == -1 )
  62.                 return -1;

  63.         /** build address and bind it to socket **/

  64.         bzero((void *)&saddr, sizeof(saddr));   /* clear out struct     */
  65.         gethostname(hostname, HOSTLEN);         /* where am I ?         */
  66.         hp = gethostbyname(hostname);           /* get info about host  */
  67.                                                 /* fill in host part    */
  68.         bcopy( (void *)hp->h_addr, (void *)&saddr.sin_addr, hp->h_length);
  69.         saddr.sin_port = htons(portnum);        /* fill in socket port  */
  70.         saddr.sin_family = AF_INET ;            /* fill in addr family  */
  71.         if ( bind(sock_id, (struct sockaddr *)&saddr, sizeof(saddr)) != 0 )
  72.                return -1;

  73.         /** arrange for incoming calls **/

  74.         if ( listen(sock_id, backlog) != 0 )
  75.                 return -1;
  76.         return sock_id;
  77. }

  78. /*
  79. * initialize the status variables and
  80. * set the thread attribute to detached
  81. */
  82. setup(pthread_attr_t *attrp)
  83. {
  84.         pthread_attr_init(attrp);
  85.         pthread_attr_setdetachstate(attrp,PTHREAD_CREATE_DETACHED);

  86.         time(&server_started);
  87.         server_requests = 0;
  88.         server_bytes_sent = 0;
  89. }

  90. void *handle_call(void *fdptr)
  91. {
  92.         FILE        *fpin;
  93.         char        request[BUFSIZ];
  94.         int        fd ;

  95.         fd = *(int *)fdptr;
  96.         free(fdptr);                                /* get fd from arg  */

  97.         fpin = fdopen(fd, "r");                        /* buffer input        */
  98.         fgets(request,BUFSIZ,fpin);                /* read client request */
  99.         printf("got a call on %d: request = %s", fd, request);
  100.         skip_rest_of_header(fpin);

  101.         process_rq(request, fd);                /* process client rq */

  102.         fclose(fpin);
  103. }

  104. /* ------------------------------------------------------ *
  105.    skip_rest_of_header(FILE *)
  106.    skip over all request info until a CRNL is seen
  107.    ------------------------------------------------------ */
  108. skip_rest_of_header(FILE *fp)
  109. {
  110.         char        buf[BUFSIZ];
  111.         while( fgets(buf,BUFSIZ,fp) != NULL && strcmp(buf,"\r\n") != 0 )
  112.                 ;
  113. }

  114. /* ------------------------------------------------------ *
  115.    process_rq( char *rq, int fd )
  116.    do what the request asks for and write reply to fd
  117.    handles request in a new process
  118.    rq is HTTP command:  GET /foo/bar.html HTTP/1.0
  119.    ------------------------------------------------------ */
  120. process_rq( char *rq, int fd)
  121. {
  122.         char        cmd[BUFSIZ], arg[BUFSIZ];

  123.         if ( sscanf(rq, "%s%s", cmd, arg) != 2 )
  124.                 return;
  125.         sanitize(arg);
  126.         printf("sanitized version is %s\n", arg);

  127.         if ( strcmp(cmd,"GET") != 0 )
  128.                 not_implemented();
  129.         else if ( built_in(arg, fd) )
  130.                 ;
  131.         else if ( not_exist( arg ) )
  132.                 do_404(arg, fd);
  133.         else if ( isadir( arg ) )
  134.                 do_ls( arg, fd );
  135.         else
  136.                 do_cat( arg, fd );
  137. }
  138. /*
  139. * make sure all paths are below the current directory
  140. */
  141. sanitize(char *str)
  142. {
  143.         char        *src, *dest;

  144.         src = dest = str;

  145.         while( *src ){
  146.                 if( strncmp(src,"/../",4) == 0 )
  147.                         src += 3;
  148.                 else if ( strncmp(src,"//",2) == 0 )
  149.                         src++;
  150.                 else
  151.                         *dest++ = *src++;
  152.         }
  153.         *dest = '\0';
  154.         if ( *str == '/' )
  155.                 strcpy(str,str+1);

  156.         if ( str[0]=='\0' || strcmp(str,"./")==0 || strcmp(str,"./..")==0 )
  157.                 strcpy(str,".");
  158. }

  159. /* handle built-in URLs here.  Only one so far is "status" */
  160. built_in(char *arg, int fd)
  161. {
  162.         FILE        *fp;

  163.         if ( strcmp(arg,"status") != 0 )
  164.                 return 0;
  165.         http_reply(fd, &fp, 200, "OK", "text/plain",NULL);

  166.         fprintf(fp,"Server started: %s", ctime(&server_started));
  167.         fprintf(fp,"Total requests: %d\n", server_requests);
  168.         fprintf(fp,"Bytes sent out: %d\n", server_bytes_sent);
  169.         fclose(fp);
  170.         return 1;
  171. }

  172. http_reply(int fd, FILE **fpp, int code, char *msg, char *type, char *content)
  173. {
  174.         FILE        *fp = fdopen(fd, "w");
  175.         int        bytes = 0;

  176.         if ( fp != NULL ){
  177.                 bytes = fprintf(fp,"HTTP/1.0 %d %s\r\n", code, msg);
  178.                 bytes += fprintf(fp,"Content-type: %s\r\n\r\n", type);
  179.                 if ( content )
  180.                         bytes += fprintf(fp,"%s\r\n", content);
  181.         }
  182.         fflush(fp);
  183.         if ( fpp )
  184.                 *fpp = fp;
  185.         else
  186.                 fclose(fp);
  187.         return bytes;
  188. }

  189. /* ------------------------------------------------------ *
  190.    simple functions first:
  191.         not_implemented(fd)      unimplemented HTTP command
  192.         and do_404(item,fd)     no such object
  193.    ------------------------------------------------------ */
  194. not_implemented(int fd)
  195. {
  196.         http_reply(fd,NULL,501,"Not Implemented","text/plain",
  197.                         "That command is not implemented");
  198. }

  199. do_404(char *item, int fd)
  200. {
  201.         http_reply(fd,NULL,404,"Not Found","text/plain",
  202.                         "The item you seek is not here");
  203. }

  204. /* ------------------------------------------------------ *
  205.    the directory listing section
  206.    isadir() uses stat, not_exist() uses stat
  207.    ------------------------------------------------------ */
  208. isadir(char *f)
  209. {
  210.         struct stat info;
  211.         return ( stat(f, &info) != -1 && S_ISDIR(info.st_mode) );
  212. }

  213. not_exist(char *f)
  214. {
  215.         struct stat info;
  216.         return( stat(f,&info) == -1 );
  217. }

  218. do_ls(char *dir, int fd)
  219. {
  220.         DIR              *dirptr;
  221.         struct dirent *direntp;
  222.         FILE              *fp;
  223.         int              bytes = 0;

  224.         bytes = http_reply(fd,&fp,200,"OK","text/plain",NULL);
  225.         bytes += fprintf(fp,"Listing of Directory %s\n", dir);

  226.         if ( (dirptr = opendir(dir)) != NULL ){
  227.                 while( direntp = readdir(dirptr) ){
  228.                         bytes += fprintf(fp, "%s\n", direntp->d_name);
  229.                 }
  230.                 closedir(dirptr);
  231.         }
  232.         fclose(fp);
  233.         server_bytes_sent += bytes;
  234. }

  235. /* ------------------------------------------------------ *
  236.    functions to cat files here.
  237.    file_type(filename) returns the 'extension': cat uses it
  238.    ------------------------------------------------------ */
  239. char * file_type(char *f)
  240. {
  241.         char        *cp;
  242.         if ( (cp = strrchr(f, '.' )) != NULL )
  243.                 return cp+1;
  244.         return "";
  245. }

  246. /* do_cat(filename,fd): sends header then the contents */

  247. do_cat(char *f, int fd)
  248. {
  249.         char        *extension = file_type(f);
  250.         char        *type = "text/plain";
  251.         FILE        *fpsock, *fpfile;
  252.         int        c;
  253.         int        bytes = 0;

  254.         if ( strcmp(extension,"html") == 0 )
  255.                 type = "text/html";
  256.         else if ( strcmp(extension, "gif") == 0 )
  257.                 type = "image/gif";
  258.         else if ( strcmp(extension, "jpg") == 0 )
  259.                 type = "image/jpeg";
  260.         else if ( strcmp(extension, "jpeg") == 0 )
  261.                 type = "image/jpeg";

  262.         fpsock = fdopen(fd, "w");
  263.         fpfile = fopen( f , "r");
  264.         if ( fpsock != NULL && fpfile != NULL )
  265.         {
  266.                 bytes = http_reply(fd,&fpsock,200,"OK",type,NULL);
  267.                 while( (c = getc(fpfile) ) != EOF ){
  268.                         putc(c, fpsock);
  269.                         bytes++;
  270.                 }
  271.                 fclose(fpfile);
  272.                 fclose(fpsock);
  273.         }
  274.         server_bytes_sent += bytes;
  275. }

复制代码

作者: tintin116    时间: 2006-06-22 12:33
顶一个
作者: liuke432    时间: 2006-06-22 15:34
这么好的实践例子怎么没人顶呢?    :(
作者: rwen2012    时间: 2006-06-22 20:52
UP--
作者: liuke432    时间: 2006-06-23 10:56
自己顶!  ^~^
作者: 新手上路2世    时间: 2006-06-23 11:41
好东东! 支持!
作者: 莫愁    时间: 2006-06-23 11:43
支持这样的实践活动!
作者: hezhiroy    时间: 2006-06-23 13:08
收藏
作者: backhamer    时间: 2006-06-24 15:14
好东西啊,收藏!
作者: hello386    时间: 2006-06-24 16:04
好 顶
呵呵
作者: backhamer    时间: 2006-06-28 09:49
UP!
作者: cppstl    时间: 2006-06-29 02:23
我telnet www.xxx.com 80
连接成功之后我无法输入任务字符,why?
作者: liuke432    时间: 2006-06-29 15:15
输入 $telnet  www.ouc.edu.cn  80
会出现
Trying 211.64.150.68...
Connected to www.ouc.edu.cn(211.64.150.6
Escape character is '^]'.
然后输入
GET /index.html HTTP/1.0
              
<注意包含一空行>
然后会出现
HTTP/1.1  200  OK
Date: Wed, 21 Jun 2006  08:26:04 GMT
Server: Apache/2.0.54(Unix) DAV/2
.......
作者: manio    时间: 2006-10-14 09:01
提示: 作者被禁止或删除 内容自动屏蔽
作者: JohnBull    时间: 2006-10-15 21:51
非原创代码,不应评为原创精华。
原始代码:
http://utopia.poly.edu/~lzinge01/server_V0.03A.c
作者: W.Z.T    时间: 2007-01-01 12:51
楼主的代码取自<<Unix/Linux编程实践教程>>第12章,连注释都一样!~
作者: langue    时间: 2007-01-01 20:35
嗯,这个程序可以作为 Web 服务器面向服务的典型案例学习啦。因为它不是面向标准的,离标准还有不小的距离。

不过,这样的程序往往具有指导意义,所以我也支持一下

无论是原创还是转帖,都十分有意义
作者: ngzyl    时间: 2007-01-01 22:39
好贴,顶。。。。。。。。。。。。。。UP

好好好。。。。
作者: benjiam    时间: 2007-01-04 14:32
看steven 的书吧。 只有前2章的内容
作者: sunday1207    时间: 2007-02-03 19:10
有兴趣的可以去看看MINI HTTP的原代码,很小,只有4-5K,一个完整的HTTP服务器代码
作者: janusle    时间: 2007-02-03 23:54
强烈支持,我以前用Python写过一个,呵呵单线程的。有空用C也写写,到时候可以拿来做参考
作者: superweak    时间: 2013-02-01 17:07
本来不想打击的,但是这个程序你到底想fork多少个进程?
作者: freshxman    时间: 2013-02-01 17:30
提示: 作者被禁止或删除 内容自动屏蔽




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2