Web客户端和服务器之间的交互用的是一个基于文本的应用级协议,叫做HTTP(hypertext transfer protocol)
web服务器以两种不同的方式向客户端提供内容:
1,取一个磁盘文件,并将它的内容返回给客户端,磁盘文件称为静态内容,而返回文件给客户端的过程称为服务静态内容。
2,运行一个可执行文件,并将它的内容返回给客户端,运行时可执行文件产生的输出称为动态内容,而运行程序返回它的
输出到客户端的过程称为服务动态内容。
关于http响应,下面是一些http状态码
状态代码 状态消息 描述
200 成功 处理请求无误
301 永久移动 内容已移动到位置头中指明的主机上
400 错误请求 服务器不能理解请求
403 禁止 服务器无权访问所请求的文件
404 未发现 服务器不能找到所请求的文件
501 未实现 服务器不支持请求的方法
505 HTTP版本不支持 服务器不支持请求的版本
如果我们思考一下,一个服务器是如何向客户端提供静态内容的,就会发现一个问题,例如,客户端如何将程序参数传递给
服务器,服务器如何将参数传递给它所创建的子进程,子进程的输出发送到哪里?一个称为CGI的实际标准的出现解决了这些
问题(common gateway interface)。
2:服务器如何将参数传递给子进程
在服务器接收到一个如下的请求后:
GET /cgi-bin/adder?1500&213 HTTP/1.1
它调用fork创建一个子进程,并调用execve在子进程的上下文中执行/cgi-bin/adder程序,在调用execve之前,子进程将cgi环境
变量QUERY_STRING设置为"1500&213",adder程序在运行时可以用getenv函数来应用它
3,服务器如何将其他信息传递给子进程
cgi标准定义了大量的其他环境变量,一个cgi程序在它运行时可以设置这些环境变量
环境变量 描述
QUERY_STRING 程序参数
SERVER_PORT 父进程侦听的端口
REQUEST_METHOD GET或POST
REMOTE_HOST 客户端的域名
REMOTE_ADDR 客户端的点分十进制IP地址
CONTENT_TYPE 只对POST而言:请求体的MIME类型
CONTENT_LENGTH 只对POST而言:请求体的字节大小
4, 子进程将它的输出发送到哪里
一个CGI程序将它的动态内容发送到标准输出,在子进程加载并运行CGI程序之前,它使用dup2函数将标准输出重定向到和客户端
相关联的已连接描述符,因此,任何CGI程序写到标准输出的东西会直接到达客户端。
注意,因为父进程不知道子进程生成的内容的类型和大小,所以子进程就要负责生成content-type和content-length响应报头,以及
终止报头的空行。
对于post请求,子进程也需要重定向标准输入到已连接描述符,然后,cgi程序会从标准输入中读取请求主题中的参数
tiny web服务器
int main(int argc,char* argv[]){
listenfd = open_listenfd(port);
while(1){
connfd = accept(listenfd,....);
doit(connfd);
close(connfd)
}
}
voidn doit(int fd){
if(static){
serve_static(fd,filename,filesize);
}
if(dynamic){
serve_dynamic(fd,filename,cgiargs);
}
}
void server_static(fd,...){
int srcfd;
sprintf("buf","HTTP/1.0 200 OK\r\n");
//...send response header to client
write(fd,buf,strlen(buf));
srcfd = open(filename,O_RDONLY,0);
p = mmap(0,filesize,PORT_READ,MAP_PRIVATE,srcfd,0);
write(fd,p,filesize);
munmap(p,filesize);
}
void serve_dynamic(int fd,char* filename,char* cigargs)
{
//1:send header http/1.0 200 ok
if(fork() == 0){
setenv("query_string",cgiargs,1);
dup2(fd,STDOUT_FILENO);
execve(filename,...);
}
wait(NULL);
}
注意:因为cgi程序运行在子进程的上下文中,它能够访问所有在调用execve函数之前就存在的打开文件和环境变量。
因此cgi程序的标准输出上的任何东西都将直接送达到客户端进程,不会受到来自任何父进程的干涉.