一个web服务器的实现(上)

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

例如:
$telnet  www.ouc.edu.cn  80
Trying 211.64.150.68...
Connected to www.ouc.edu.cn(211.64.150.68)
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就可以访问。
标签: HTTP

代码片段(1)[全屏查看所有代码]

1. [代码]webserv.c     跳至 [1] [全屏预览]

001 /* webserv.c - a web server
002  
003  *      build: gcc webserv.c -o webserv
004  
005  */
006  
007 #include    <stdio.h>
008  
009 #include    <unistd.h>
010  
011 #include    <sys/types.h>
012  
013 #include    <sys/socket.h>
014  
015 #include    <netinet/in.h>
016  
017 #include    <netdb.h>
018  
019 #include    <sys/stat.h>
020  
021 #include    <time.h>
022  
023 #include    <string.h>
024  
025  
026  
027 #define   HOSTLEN  256
028  
029 #define   BACKLOG  1
030  
031  
032  
033  
034  
035 main(int ac, char *av[])
036  
037 {
038  
039     int     sock, fd;
040  
041     FILE    *fpin;
042  
043     char    request[BUFSIZ];
044  
045  
046  
047     if ( ac == 1 ){
048  
049         fprintf(stderr,"usage: ws portnum\n");
050  
051         exit(1);
052  
053     }
054  
055     sock = make_server_socket( atoi(av[1]) );
056  
057     if ( sock == -1 ) exit(2);
058  
059  
060  
061     /* main loop here */
062  
063  
064  
065     while(1){
066  
067         /* take a call and buffer it */
068  
069         fd = accept( sock, NULL, NULL );
070  
071         fpin = fdopen(fd, "r" );
072  
073  
074  
075         /* read request */
076  
077         fgets(request,BUFSIZ,fpin);
078  
079         printf("got a call: request = %s", request);
080  
081         read_til_crnl(fpin);
082  
083  
084  
085         /* do what client asks */
086  
087         process_rq(request, fd);
088  
089  
090  
091         fclose(fpin);
092  
093     }
094  
095 }
096  
097  
098  
099 /* ------------------------------------------------------ *
100  
101    make_server_socket(int portnum)
102  
103    创建一个服务器套接字,并调用listen监听
104  
105    ------------------------------------------------------ */
106  
107  
108  
109 int make_server_socket(int portnum)
110  
111 {
112  
113     return make_server_socket_q(portnum, BACKLOG);
114  
115 }
116  
117 int make_server_socket_q(int portnum, int backlog)
118  
119 {
120  
121     struct  sockaddr_in   saddr;   /* build our address here */
122  
123     struct  hostent     *hp;   /* this is part of our    */
124  
125     char    hostname[HOSTLEN];     /* address            */
126  
127     int sock_id;           /* the socket             */
128  
129  
130  
131     sock_id = socket(PF_INET, SOCK_STREAM, 0);  /* get a socket */
132  
133     if ( sock_id == -1 )
134  
135         return -1;
136  
137  
138  
139     /** build address and bind it to socket **/
140  
141  
142  
143     bzero((void *)&saddr, sizeof(saddr));   /* clear out struct     */
144  
145     gethostname(hostname, HOSTLEN);         /* where am I ?         */
146  
147     hp = gethostbyname(hostname);           /* get info about host  */
148  
149                                             /* fill in host part    */
150  
151     bcopy( (void *)hp->h_addr, (void *)&saddr.sin_addr, hp->h_length);
152  
153     saddr.sin_port = htons(portnum);        /* fill in socket port  */
154  
155     saddr.sin_family = AF_INET ;            /* fill in addr family  */
156  
157     if ( bind(sock_id, (struct sockaddr *)&saddr, sizeof(saddr)) != 0 )
158  
159            return -1;
160  
161  
162  
163     /** arrange for incoming calls **/
164  
165  
166  
167     if ( listen(sock_id, backlog) != 0 )
168  
169         return -1;
170  
171     return sock_id;
172  
173 }
174  
175  
176  
177  
178  
179 /* ------------------------------------------------------ *
180  
181    read_til_crnl(FILE *)
182  
183    skip over all request info until a CRNL is seen
184  
185    ------------------------------------------------------ */
186  
187  
188  
189 read_til_crnl(FILE *fp)
190  
191 {
192  
193     char    buf[BUFSIZ];
194  
195     whilefgets(buf,BUFSIZ,fp) != NULL && strcmp(buf,"\r\n") != 0 )
196  
197         ;
198  
199 }
200  
201  
202  
203
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值