深入理解计算机系统服务器_第1页
深入理解计算机系统服务器_第2页
深入理解计算机系统服务器_第3页
深入理解计算机系统服务器_第4页
深入理解计算机系统服务器_第5页
已阅读5页,还剩6页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、本文是我学习<深入理解计算机系统>中网络编程部分的学习笔记。1. Web基础      web客户端和服务器之间的交互使用的是一个基于文本的应用级协议HTTP(超文本传输协议)。一个web客户端(即浏览器)打开一个到服务器的因特网连接,并且请求某些内容。服务器响应所请求的内容,然后关闭连接。浏览器读取这些内容,并把它显示在屏幕上。       对于web客户端和服务器而言,内容是与一个MIME类型相关的字节序列。常见的MIME类型:        MIME类型 &

2、#160;描述text/html       HTML页面text/plain 无格式文本image/gif    GIF格式编码的二进制图像image/jpeg    JPEG格式编码的二进制图像     web服务器以两种不同的方式向客服端提供内容:(1)静态内容:取一个磁盘文件,并将它的内容返回给客户端(2)动态内容:执行一个可执行文件,并将它的输出返回给客户端 统一资源定位符:URL:80/index.html表示因特网主机 上一个称为 index.html

3、 的HTML文件,它是由一个监听端口80的Web服务器所管理的。 HTTP默认端口号为80可执行文件的URL可以在文件名后包括程序参数, “?”字符分隔文件名和参数,而且每个参数都用“&”字符分隔开,如::8000/cgi-bin/adder?123&456表示一个 /cgi-bin/adder 的可执行文件,带两个参数字符串为 123 和 456确定一个URL指向的是静态内容还是动态内容没有标准的规则,常见的方法就是把所有的可执行文件都放在 cgi-bin 目录中 2. HTTPHTTP标准要求每个文本行都由

4、一对回车和换行符来结束 (1)HTTP请求一个HTTP请求:一个请求行(request line) 后面跟随0个或多个请求报头(request header), 再跟随一个空的文本行来终止报头 请求行: <method> <uri> <version>HTTP支持许多方法,包括 GET,POST,PUT,DELETE,OPTIONS,HEAD,TRACE。URI是相应URL的后缀,包括文件名和可选参数version 字段表示该请求所遵循的HTTP版本 请求报头:<header name> : <header d

5、ata> 为服务器提供了额外的信息,例如浏览器的版本类型HTTP 1.1中 一个IP地址的服务器可以是 多宿主主机,例如   可以存在于同一服务器上。HTTP 1.1 中必须有 host 请求报头,如 host:80  如果没有这个host请求报头,每个主机名都只有唯一IP,IP地址很快将用尽。 (2)HTTP响应一个HTTP响应:一个响应行(response line) 后面跟随0个或多个响应报头(response header),再跟随一个空的文本行来终止报头,最后跟随一个响应主体(response body) 响应行:<version&

6、gt; <status code> <status message>status code 是一个三位的正整数                 状态代码状态消息描述200成功 处理请求无误301 永久移动  内容移动到位置头中指明的主机上400错误请求服务器不能理解请求403 禁止 服务器无权访问所请求的文件404未发现 服务器不能找到所请求的文件501 未实现服务器不支持请求的方法505 HTTP版本

7、不支持服务器不支持请求的版本 两个最重要的响应报头:Content-Type 告诉客户端响应主体中内容的MIME类型Content-Length 指示响应主体的字节大小响应主体中包含着被请求的内容。 3.服务动态内容(1) 客户端如何将程序参数传递给服务器GET请求的参数在URI中传递, “?”字符分隔了文件名和参数,每个参数都用一个"&"分隔开,参数中不允许有空格,必须用字符串“%20”来表示HTTP POST请求的参数是在请求主体中而不是 URI中传递的 (2)服务器如何将参数传递给子进程GET /cgi-bin/adder?123

8、&456 HTTP/1.1它调用 fork 来创建一个子进程,并调用 execve 在子进程的上下文中执行 /cgi-bin/adder 程序在调用 execve 之前,子进程将CGI环境变量 QUERY_STRING 设置为"123&456", adder 程序在运行时可以用unix getenv 函数来引用它 (3)服务器如何将其他信息传递给子进程           环境变量 描述QUERY_STRING程序参数SERVER_PORT 父进程侦

9、听的端口REQUEST_METHODGET 或 POSTREMOTE_HOST客户端的域名REMOTE_ADDR 客户端的点分十进制IP地址CONTENT_TYPE只对POST而言,请求体的MIME类型CONTENT_LENGTH只对POST而言,请求体的字节大小  (4) 子进程将它的输出发送到哪里一个CGI程序将它的动态内容发送到标准输出,在子进程加载并运行CGI程序之前,它使用UNIX dup2 函数将它标准输出重定向到和客户端相关连的已连接描述符因此,任何CGI程序写到标准输出的东西都会直接到达客户端 4. 综合: Tiny web 服务器

10、60;(1) main程序Tiny是一个迭代服务器,监听在命令行中传递来的端口上的连接请求,在通过调用 open_listenfd 函数打开一个监听套接字以后,执行无限服务器循环,不断接受连接请求(第16行),执行事务(第17行),并关闭连接它的那一端(第18行) 1 int main(int argc, char *argv) 2 3 int listenfd, connfd, port, clientlen; 4 struct sockaddr_in clientaddr; 5 6 /* Check command line args */ 7 if (argc != 2) 8 fprin

11、tf(stderr, "usage: %s <port>n", argv0); 9 exit(1);10 11 port = atoi(argv1);12 13 listenfd = Open_listenfd(port);14 while (1) 15 clientlen = sizeof(clientaddr);16 connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen); /line:netp:tiny:accept17 doit(connfd); /line:netp:tiny:d

12、oit18 Close(connfd); /line:netp:tiny:close19 20  (2) doit函数doit函数处理一个HTTP事物,首先读和解析请求行(request line)(第11-12行),注意,我们使用rio_readlineb函数读取请求行。Tiny只支持GET方法,如果客户端请求其他方法,发送一个错误信息。然后将URI解析为一个文件名和一个可能为空的CGI参数字符串,并且设置一个标志表明请求的是静态内容还是动态内容(第21行)如果请求的是静态内容,就验证是否为普通文件,有读权限(第29行) 如果请求的是动态内容,就验证是否为可执行文件(第3

13、7行),如果是,就提供动态内容(第42行) 1 void doit(int fd) 2 3 int is_static; 4 struct stat sbuf; 5 char bufMAXLINE, methodMAXLINE, uriMAXLINE, versionMAXLINE; 6 char filenameMAXLINE, cgiargsMAXLINE; 7 rio_t rio; 8 9 /* Read request line and headers */10 Rio_readinitb(&rio, fd);11 Rio_readlineb(&rio, buf, MA

14、XLINE); /line:netp:doit:readrequest12 sscanf(buf, "%s %s %s", method, uri, version); /line:netp:doit:parserequest13 if (strcasecmp(method, "GET") /line:netp:doit:beginrequesterr14 clienterror(fd, method, "501", "Not Implemented",15 "Tiny does not implemen

15、t this method");16 return;17 /line:netp:doit:endrequesterr18 read_requesthdrs(&rio); /line:netp:doit:readrequesthdrs19 20 /* Parse URI from GET request */21 is_static = parse_uri(uri, filename, cgiargs); /line:netp:doit:staticcheck22 if (stat(filename, &sbuf) < 0) /line:netp:doit:beg

16、innotfound23 clienterror(fd, filename, "404", "Not found",24 "Tiny couldn't find this file");25 return;26 /line:netp:doit:endnotfound27 28 if (is_static) /* Serve static content */ 29 if (!(S_ISREG(sbuf.st_mode) | !(S_IRUSR & sbuf.st_mode) /line:netp:doit:readab

17、le30 clienterror(fd, filename, "403", "Forbidden",31 "Tiny couldn't read the file");32 return;33 34 serve_static(fd, filename, sbuf.st_size); /line:netp:doit:servestatic35 36 else /* Serve dynamic content */37 if (!(S_ISREG(sbuf.st_mode) | !(S_IXUSR & sbuf.st_mo

18、de) /line:netp:doit:executable38 clienterror(fd, filename, "403", "Forbidden",39 "Tiny couldn't run the CGI program");40 return;41 42 serve_dynamic(fd, filename, cgiargs); /line:netp:doit:servedynamic43 44 (3)clienterror函数clienterror函数检查一些明显的错误,并把它报告给客户端 void c

19、lienterror(int fd, char *cause, char *errnum, char *shortmsg, char *longmsg) char bufMAXLINE, bodyMAXBUF; /* Build the HTTP response body */ sprintf(body, "<html><title>Tiny Error</title>"); sprintf(body, "%s<body bgcolor=""ffffff"">rn"

20、, body); sprintf(body, "%s%s: %srn", body, errnum, shortmsg); sprintf(body, "%s<p>%s: %srn", body, longmsg, cause); sprintf(body, "%s<hr><em>The Tiny Web server</em>rn", body); /* Print the HTTP response */ sprintf(buf, "HTTP/1.0 %s %srn&quo

21、t;, errnum, shortmsg); Rio_writen(fd, buf, strlen(buf); sprintf(buf, "Content-type: text/htmlrn"); Rio_writen(fd, buf, strlen(buf); sprintf(buf, "Content-length: %drnrn", (int)strlen(body); Rio_writen(fd, buf, strlen(buf); Rio_writen(fd, body, strlen(body); (4)read_requesthd

22、rs 函数Tiny不使用请求报头中的任何信息,仅仅调用 read_requesthdrs函数来读取并忽略这些报头。注意,终止请求报头的空文本行是由 回车和换行符组成的,在第6行中检查 1 void read_requesthdrs(rio_t *rp) 2 3 char bufMAXLINE; 4 5 Rio_readlineb(rp, buf, MAXLINE); 6 while(strcmp(buf, "rn") /line:netp:readhdrs:checkterm 7 Rio_readlineb(rp, buf, MAXLINE); 8 printf(

23、"%s", buf); 9 10 return;11  (5)parse_uri 函数Tiny假设静态内容的主目录就是当前目录,可执行文件的主目录是 ./cgi-bin/ 任何包含字符串 cgi-bin 的URI都认为是对动态内容的请求。首先将URI解析为一个文件名和一个可选的CGI参数字符串。如果请求的是静态内容(第5行),就清除CGI参数串(第6行),然后将URI转换为一个相对的unix 路径名,例如 ./index.html如果URI是用'/' 结尾的(第9行) ,我们就把默认的文件名加在后面(第10行) 如果请求的是动态

24、内容(第13行),就会抽取所有的CGI参数(第14-20行),并将URI剩下的部分转换为一个相应的unix文件名(第21-22行) 1 int parse_uri(char *uri, char *filename, char *cgiargs) 2 3 char *ptr; 4 5 if (!strstr(uri, "cgi-bin") /* Static content */ /line:netp:parseuri:isstatic 6 strcpy(cgiargs, ""); /line:netp:parseuri:clearcgi 7 strcp

25、y(filename, "."); /line:netp:parseuri:beginconvert1 8 strcat(filename, uri); /line:netp:parseuri:endconvert1 9 if (uristrlen(uri)-1 = '/') /line:netp:parseuri:slashcheck10 strcat(filename, "home.html"); /line:netp:parseuri:appenddefault11 return 1;12 13 else /* Dynamic co

26、ntent */ /line:netp:parseuri:isdynamic14 ptr = index(uri, '?'); /line:netp:parseuri:beginextract15 if (ptr) 16 strcpy(cgiargs, ptr+1);17 *ptr = '0'18 19 else 20 strcpy(cgiargs, ""); /line:netp:parseuri:endextract21 strcpy(filename, "."); /line:netp:parseuri:beginc

27、onvert222 strcat(filename, uri); /line:netp:parseuri:endconvert223 return 0;24 25  (6)serve_static 函数Tiny提供四种不同的静态内容:HTML文件、无格式的文本文件、GIF编码格式图片、JPEG编码格式图片serve_static 函数发送一个HTTP响应,其主体包含一个本地文件的内容。首先我们通过检查文件名的后缀来判断文件类型(第7行),并且发送响应行和响应报头给客户端(第8-12行)。注意用一个空行终止报头第16行,我们使用 unix mmap函数将被请求文件映射到一个虚

28、拟问存储器空间,调用mmap将文件srcfd的前filesize个字节映射到一个从地址srcp开始的私有只读虚拟存储器区域。一旦文件映射到存储器,就不再需要它的描述符了,关闭这个文件(第17行)。第18行执行的是到客户端的实际文件传动。rio_writen 函数拷贝从srcp位置开始的filesize个字节(已经被映射到了所请求的文件) 到客户端的已连接描述符。第19行释放了映射的虚拟存储器区域,避免潜在的存储器泄漏  1 void serve_static(int fd, char *filename, int filesize) 2 3 int srcfd; 4 char *sr

29、cp, filetypeMAXLINE, bufMAXBUF; 5 6 /* Send response headers to client */ 7 get_filetype(filename, filetype); /line:netp:servestatic:getfiletype 8 sprintf(buf, "HTTP/1.0 200 OKrn"); /line:netp:servestatic:beginserve 9 sprintf(buf, "%sServer: Tiny Web Serverrn", buf);10 sprintf(bu

30、f, "%sContent-length: %drn", buf, filesize);11 sprintf(buf, "%sContent-type: %srnrn", buf, filetype);12 Rio_writen(fd, buf, strlen(buf); /line:netp:servestatic:endserve13 14 /* Send response body to client */15 srcfd = Open(filename, O_RDONLY, 0); /line:netp:servestatic:open16 sr

31、cp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0);/line:netp:servestatic:mmap17 Close(srcfd); /line:netp:servestatic:close18 Rio_writen(fd, srcp, filesize); /line:netp:servestatic:write19 Munmap(srcp, filesize); /line:netp:servestatic:munmap20 21 22 /*23 * get_filetype - derive file type from

32、 file name24 */25 void get_filetype(char *filename, char *filetype) 26 27 if (strstr(filename, ".html")28 strcpy(filetype, "text/html");29 else if (strstr(filename, ".gif")30 strcpy(filetype, "image/gif");31 else if (strstr(filename, ".jpg")32 strcpy(filetype, "image/jpeg");33 else34 strcpy(filetype, "text/plain");35  (6)serve

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论