版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、Web服务器实现高崇铭2012001010016简单Web服务器详细设计说明书英才实验1班高崇铭20120010100161、引言:本程序为windous下用C+语言实现的简单的一个Web服务器,其功能很简单,开启时候能够监听到外部客户端发来的HTTP请求,解析请求文件,在本机进行搜索,最终以HTTP报文形式返回该文件。由于这只是一个简单的服务器架构,并没有考虑很好的鲁棒性,即返回报文中只有200 OK的字段,并未考虑其他可能性。但在该程序的基础上,这些功能都很容易扩展。整个程序的思路框架如下图:2、组织结构:3、程序:3.1:主函数(1)函数:main(int argc, char *arg
2、v)(2)函数功能:包含socket(),bind(),listen(),accept(),recv(),closesocket()这一系列的套接字函数,负责建立套接字,绑定套接字与本机信息,分配端口号,监听并接收来自服务器的请求报文,将HTTP报文交给解析函数http_send_response(),最后关闭套接字。(3)参数说明:int argc: 参数个数char *argv: 端口号(4)返回值:空特殊说明:所用socket函数如下:(1)函数:socket( int af, int type, int protocol);(2)函数功能:创建一个套接字,出现在地址族中,但并未赋名。即
3、只是创建了一个套接字的描述,此时没有IP和端口号与其关联。(3)参数说明:af:一个地址描述。目前仅支持AF_INET格式,也就是说ARPA Internet地址格式。type:指定socket类型。其中所用SOCK_STREAM 提供有序的、可靠的、双向的和基于连接的字节流,使用带外数据传送机制,为Internet地址族使用TCPprotocol:指定协议,0为缺省。(4)返回值:若创建套接字失败,则返回INVALID_SOCKET。(1)函数:bind( SOCKET s, const struct sockaddr FAR* name,int namelen);(2)函数功能:将一本地地
4、址与一套接口捆绑。本函数适用于未连接的数据报或流类套接口,在connect()或listen()调用前使用。当用socket()创建套接口后,它便存在于一个名字空间(地址族)中,但并未赋名。bind()函数通过给一个未命名套接口分配一个本地名字来为套接口建立本地捆绑(主机地址/端口号)。(3)参数说明:s:标识一未捆绑套接口的描述字。name:赋予套接口的地址。namelen:name名字的长度。(4)返回值:绑定成功返回0,失败返回-1或SOCKET_ERROR(1)函数:listen( SOCKET s, int backlog);(2)函数功能:Listen()将上一步bind()函数绑
5、定过IP与端口号的套接字申请进入的连接建立一个后备日志,即为监听连接请求(3)参数说明:s:标识一未捆绑套接口的描述字。name:赋予套接口的地址。namelen:name名字的长度。(4)返回值:绑定成功返回0,失败返回-1或SOCKET_ERROR(1)函数:accept( SOCKET s, struct sockaddr * addr,int * addrlen);(2)函数功能:在到达listen()监听函数的请求连接队列中抽取第一个连接,创建一个相同SOCKET类型的套接字并返回句柄,即赋予新的端口号(3)参数说明:s:套接口描述字,该套接口在listen()后监听连接。addr:
6、(可选)指针,指向一缓冲区,其中接收为通讯层所知的连接实体的地址。addr参数的实际格式由套接口创建时所产生的地址族确定。addrlen:(可选)指针,输入参数,配合addr一起使用,指向存有addr地址长度的整型数。(4)返回值:成功返回一个新的套接字描述符,失败返回-1或INVALID_SOCKET。(1)函数:recv( SOCKET s, char FAR* buf, int len, int flags);(2)函数功能:如果s的发送缓冲中没有数据或者数据被协议成功发送完毕后,recv先检查套接字s的接收缓冲区,如果s接收缓冲区中没有数据或者协议正在接收数据,那么
7、recv就一直等待,直到协议把数据接收完毕。当协议把数据接收完毕,recv函数就把s的接收缓冲中的数据copy到buf中(注意协议接收到的数据可能大于buf的长度,所以在这种情况下要调用几次recv函数才能把s的接收缓冲中的数据copy完。recv函数仅仅是copy数据,真正的接收数据是协议来完成的);(3)参数说明:s:一个标识已连接套接口的描述字。buf:用于接收数据的缓冲区。len:缓冲区长度。flags:指定调用方式。(4)返回值:正常时返回其实际copy的字节数。在copy时出错,那么它返回SOCKET_ERROR。在等待协议接收数据时网络中断,返回0。(1)函数:closesock
8、et( SOCKET s);(2)函数功能:本函数关闭一个套接口。更确切地说,它释放套接口描述字s,以后对s的访问均以WSAENOTSOCK错误返回。若本次为对套接口的最后一次访问,则相应的名字信息及数据队列都将被释放。(3)参数说明:s:一个用于标识已连接套接口的描述字。(4)返回值:无错误发生返回0。否则返回SOCKET_ERROR。3.2发送相应报文函数:(1)函数:http_send_response(SOCKET soc, char *buf, int buf_len)(2)函数功能:调用http_parse_request_cmd()函数,得到文件名、文件路径、类型(后缀)。用fo
9、pen()打开该文件,获得文件长度信息。发送HTTP相应报文头部。分段发送文件内容到套接字缓冲区。(3)参数说明:Soc: 连接套接字buf,:缓冲区数组buf_len: 缓冲区数组的大小(4)返回值:成功返回1,失败返回0特殊说明:(1)函数:send( SOCKET s, const char FAR* buf, int len, int flags);(2)函数功能:用于向一个已经连接的socket发送数据。对于数据报类套接口,必需注意发送数据长度不应超过通讯子网的IP包最大长度。成功地完成send()调用并不意味着数据传送到达。如果传送系统的缓冲区空间不够保存需传送的数据,除非套接口处
10、于非阻塞I/O方式,否则send()将阻塞。(3)参数说明:s:一个用于标识已连接套接口的描述字。buf:包含待发送数据的缓冲区。len:缓冲区中数据的长度。flags:调用执行方式。(4)返回值:正常时返回所发送数据的总数(请注意这个数字可能小于len中所规定的大小)。错误则返回SOCKET_ERROR。3.3解析报文函数:(1)函数:http_parse_request_cmd(char *buf, int buflen, char *file_name,char *file_path, char *suffix) (2)函数功能:通过buf里的http请求报文,得到所需要文件路径、文件名
11、,后缀,调用http_get_type_by_suffix()函数得知该后缀所属类型。返回值为空(3)参数说明:buf,:缓冲区数组buflen: 缓冲区数组的大小file_name:文件名指针file_path:文件路径指针suffix:文件后缀指针(4)返回值:无注意事项:程序生成的exe要与请求的本地文件放在同一个目录下,之后在浏览器里输入例如::80/gcm.txt源码:#include "stdafx.h"#include <stdio.h>#include <winsock2.h>#pragma commen
12、t(lib, "ws2_32.lib") /* WinSock使用的库函数 */* 定义常量 */#define HTTP_DEF_PORT 80 /* 连接的缺省端口 */#define HTTP_BUF_SIZE 1024 /* 缓冲区的大小 */#define HTTP_FILENAME_LEN 256 /* 文件名长度 */* 定义文件类型对应的 Content-Type */struct doc_typechar *suffix; /* 文件后缀 */char *type; /* Content-Type */;struct doc_type file_type
13、= "html", "text/html" , "gif", "image/gif" , "jpeg", "image/jpeg" , "txt", "text/html", NULL, NULL ;char *http_res_hdr_tmpl = "HTTP/1.1 200 OKrn""Server: Chongming_Gao's Server rn""Accept-Ran
14、ges: bytesrn""Content-Length: %drn""Connection: closern""Content-Type: %srn""rn"/注意以空行结束。char *http_404 = "HTTP/1.1 404 Not Foundrnrn"/* 函数功能: 根据文件后缀查找对应的 Content-Type.* 参数说明: IN suffix, 文件名后缀;* 返 回 值: 成功返回文件对应的 Content-Type, 失败返回 NULL.*/char *h
15、ttp_get_type_by_suffix(const char *suffix)struct doc_type *type;for (type = file_type; type->suffix; type+)if (strcmp(type->suffix, suffix) = 0)return type->type;return NULL;/* 函数功能: 解析请求行, 得到文件名及其后缀. 请求行格式:* GET :8080/index.html HTTP/1.1* 参数说明: IN buf, 字符串指针数组;* IN buflen, buf 的长度;* OUT fi
16、le_name, 文件名;* OUT suffix, 文件名后缀;* 返 回 值: void.*/void http_parse_request_cmd(char *buf, int buflen, char *file_name,char *file_path, char *suffix)int length = 0;char *begin, *end, *bias, *path, *temp;/* 查找 URL 的开始位置 */begin = strchr(buf, ' ');begin += 2;/* 查找 URL 的结束位置 */end = strchr(begin,
17、' ');*end = 0;strcpy(file_path, begin);/得到文件绝对路径!while(temp = strchr(begin,'') !=NULL)*temp='/'bias = strrchr(begin, '/');if(bias!=NULL)length = end - bias - 1;/* 找到文件名的开始位置。从'/'到/后的file_name起始位置。*/bias+;/* 得到文件名 */elselength=end-begin;bias=begin;if (length &g
18、t; 0)memcpy(file_name, bias, length);file_namelength = 0;begin = strchr(file_name, '.');if (begin)strcpy(suffix, begin + 1);/* 函数功能: 向客户端发送 HTTP 响应.* 参数说明: IN buf, 字符串指针数组;* IN buf_len, buf 的长度;* 返 回 值: 成功返回非0, 失败返回0.*/int http_send_response(SOCKET soc, char *buf, int buf_len)int read_len, f
19、ile_len, hdr_len, send_len;char *type;char read_bufHTTP_BUF_SIZE;char http_headerHTTP_BUF_SIZE;char file_nameHTTP_FILENAME_LEN = "index.html", suffix16 = "html"char file_pathHTTP_FILENAME_LEN;FILE *res_file;/puts(buf);if(buf_len=0) return 0;/* 得到文件名和后缀 */http_parse_request_cmd(bu
20、f, buf_len, file_name,file_path, suffix);res_file=fopen(file_name, "rb+"); /* 用二进制格式打开文件 */if (res_file = NULL)if(res_file = fopen(file_path, "rb+")=NULL)printf("Web The file %s is not existedn please check the path %s and retry.nn", file_name,file_path);hdr_len = sprin
21、tf(http_header, http_404, 5, type);send(soc, http_header, hdr_len, 0);return 0;fseek(res_file, 0, SEEK_END);file_len = ftell(res_file);fseek(res_file, 0, SEEK_SET);/三句函数得到文件的长度为file_len字节。type = http_get_type_by_suffix(suffix); /* 文件对应的 Content-Type */if (type = NULL)printf("Web There is not th
22、e related content typen");return 0;/* 构造 HTTP 首部,并发送 */hdr_len = sprintf(http_header, http_res_hdr_tmpl, file_len, type);send_len = send(soc, http_header, hdr_len, 0);/send_len=1;if (send_len = SOCKET_ERROR)fclose(res_file);printf("Web Fail to send, error = %dn", WSAGetLastError();ret
23、urn 0;do /* 发送文件, HTTP 的实体主体 */read_len = fread(read_buf, sizeof(char), HTTP_BUF_SIZE, res_file);if (read_len > 0)send_len = send(soc, read_buf, read_len, 0);file_len -= read_len; while (read_len > 0) && (file_len > 0);fclose(res_file);puts("Web Transfer is completen");ret
24、urn 1;int main(int argc, char *argv)WSADATA wsa_data;SOCKET srv_soc = 0, acpt_soc; /* socket 句柄 */struct sockaddr_in serv_addr; /* 服务器地址 */struct sockaddr_in from_addr; /* 客户端地址 */char recv_bufHTTP_BUF_SIZE;unsigned short port = HTTP_DEF_PORT;/*默认制定本机80端口为服务器端口*/int from_len = sizeof(from_addr);int
25、result = 0, recv_len;puts("Web Hello! This is Chongming Gao's server!O(_)OnNow try to access :80/gcm.txt in your Browser");puts("Web NOTES:rnt1The default port is 80.Cmd to the main function with parameter passing to use other port you like.rnt2Make sure all files a
26、re in the same file folder,and the path does not contain Chinese.rnt3If you Cmd to the main function,you'd better use Absolute path instead of a relative pathnn");if (argc = 2) /* 端口号 */port = atoi(argv1);WSAStartup(MAKEWORD(2, 0), &wsa_data); /* 初始化 WinSock 资源 */srv_soc = socket(AF_INE
27、T, SOCK_STREAM, 0); /* 创建 socket */*SOCK_STREAM 提供有序的、可靠的、双向的和基于连接的字节流,使用带外数据传送机制,为Internet地址族使用TCP*/if (srv_soc = INVALID_SOCKET)/套接字创建失败printf("Web socket() Fails, error = %dn", WSAGetLastError();return -1;/* 服务器地址 */serv_addr.sin_family = AF_INET;/TCP/IP协议serv_addr.sin_port = htons(port); /将主机序转换为网络序,网络序为大端机表示,主机序通常为小端机,注意是一个字节一个字节的转serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);/所有网卡、网关接收到发送到本机指定端口(默认80)的请求都算数。同时将转换为大端机表示result = bind(srv_soc, (struct sockaddr *) &serv_addr, sizeof(serv_addr);/给一个未命名套接口分配一个本地名字来为套接口建立本地捆绑(主机地址/端口号)if (r
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年库房转租合同转租条件、转租手续及租金处理分析
- 2024年企业内部审计保密协议
- 2024年度企业社会责任报告合同
- 2024年度住宅小区木门安装工程合同
- 2024年度许可使用合同(商标)
- 腰椎ct课件教学课件
- 2024北京技术合同
- 2024年大数据使用协议:数据收集、分析和应用的具体规定
- 液体密度课件教学课件
- 舆论学课件教学
- 2024年国际货物买卖FOB条款合同
- 华南理工大学《嵌入式系统》2022-2023学年期末试卷
- 江苏省中等职业学校学业水平考试语文卷含答案
- 售后服务保障方案3篇
- 2025届江苏省南通市海安市海安高级中学物理高三上期中联考试题含解析
- 电梯安装主要施工方法及施工技术措施
- 2024-2030年全球辣椒市场投资潜力与未来运营模式分析研究报告
- 2024-2025学年二年级上学期数学期中模拟试卷(苏教版)(含答案解析)
- 2024年天津市专业技术人员继续教育网公需课答案
- 2023-2024学年九年级上学期期末试卷及答案
- 部门安全培训试题(打印)
评论
0/150
提交评论