HTTP协议简介及web服务器搭建经验
1.HTTP概念
HTTP(超文本传输协议,HyperText Transfer Protocal)。互联网应用最为广泛的一种网络应用层协议,它可以减少网络传输,使得浏览器更加高效。通常HTTP信息包含客户机向服务器的请求消息和服务器向客户机的响应消息。
2. 请求消息
方向:浏览器→服务器,主要内容包含四部分:
- 请求行:说明请求类型,要访问的资源,以及使用的http版本
- 请求头:说明服务器要使用的附加信息
- 空行:必须要有,即使没有请求数据
- 请求数据:也称为主体,可以添加任意的其他数据
(第1行是请求行,2-8行为请求头,第9行是空行标识请求头的结束)
2.1 请求方法
-
GET
请求制定的页面信息,并返回实体主体
-
POST
向指定资源提交数据进行处理请求(例如提交表单或者上传文件),数据被包含在请求体中。POST请求可能会导致新资源的建立或者已有资源的修改
-
HEAD
类似于get的请求,只不过返回的响应中没有具体的内容,用于获取报头
-
PUT
从客户端向服务器传送的数据取代指定的文档的内容
-
DELETE
请求服务器删除指定的页面
-
CONNECT
HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器
-
OPTIONS
允许客户端查看服务器的性能
-
TRACE
回显服务器收到的请求,主要用于测试或者判断
3. 响应消息
方向:服务器→浏览器,主要内容包含四部分:
- 状态行:包括HTTP协议版本号,状态码,状态信息
- 消息报头:说明客户端要使用的一些附加信息
- 空行:必须要有
- 响应正文:服务器返回给客户端的文本信息
(每行的结尾用的是\r\n,第9行空行也是协议头的一部分)
3.1 状态码
状态码由三位数字表示,第一个数字定义了响应的类别,共分为五种类别:
- 1xx:指示信息–表示请求已经接收,继续处理
- 2xx:成功–表示请求已经被成功接收、理解、接受
- 3xx:重定向–要完成请求必须进行更进一步的操作
- 4xx:客户端错误–请求语法错误或请求无法实现
- 5xx:服务器端错误–服务器未能实现合法的请求
常见的状态码:
状态码 | 含义 |
---|---|
200 OK | 客户端请求成功 |
400 Bad Request | 客户端请求有语法错误,不能被服务器所理解 |
401 Unauthorized | 请求未授权 |
403 Forbidden | 服务器收到请求,但是拒绝提供服务 |
404 Not Found | 请求资源不存在,比如输入了错误的URL |
500 Internal Server Error | 服务器发生了不可预知的错误 |
503 Server Unavailable | 服务器当前不能处理客户端的请求 |
3.2 网络文件类型
文件类型 | HTTP语法 |
---|---|
普通文件 | text/plain;charset=ios-8859-1 |
*.html | text/html;charset=ios-8859-1 |
*.jpg | image/jpeq |
*.gif | image/gif |
*.png | image/png |
*.wav | audio/wav |
*.avi | video/x-msvidio |
*.mov | video/quicktime |
*.mp3 | audio/mpeg |
3.3 编码格式
编码格式 | 描述 |
---|---|
charset = iso-8859-1 | 西欧的编码,说明网站采用英文编码 |
charset = gb2312 | 说明网站采用的编码是简体中文 |
charset = utf-8 | 代表世界通用的语言编码,可以用到中文、日文等世界通用语言 |
charset = euc-kr | 说明网站采用的编码是韩文 |
charset = big5 | 说明网站采用的编码是繁体中文 |
4. HTTP传输流程
-
服务器getline()获取http协议第一行。
-
从首行中拆分 GET、文件名和协议版本,获取用户请求的文件名。
-
利用stat()判断文件是否存在。
-
判断文件的类型。
-
如果是文件,则open→read→写回给服务器。
-
先写HTTP应答协议头: http/1.1 200 OK
Content-Type: text/plain; charset = iso-8859-1
-
写文件数据。
5. web服务器搭建经验
5.1 正则表达式获取文件名
//请求头中包含请求方法、请求路径和请求协议类型,可以用正则表达式结合sscanf来去区分
char method[16], path[256], protocol[16];
sscanf(buf, "%[^ ] %[^ ] %[^ ]", method, path, protocol);
5.2 判断文件是否存在
//stat函数可以判断文件是否存在并获取文件的信息(包含所有ll指令显示的信息)
int ret = stat(file, &sbuf);
if(ret != 0)
{
//说明打开文件错误,比如回发404错误页面,表示URL没有找到
perror("stat judge err!");
}
if(S_ISREG(sbuf.st_mode))
{
//打印类别的信息
printf("Request regular file!\n");
//说明是一个普通文件,需要回发响应消息,respond函数已经包含了状态行、消息报头和空行了
http_respond(cfd, 200, "OK", "Content-Type:audio/mpeg",sbuf.st_size);
//然后再把文件给发送过去
send_file(cfd, file);
}
5.3 资源暂时不可用错误解决
//文件io操作的时候需要注意EAGAIN和EINTR错误,这些错误需要进行特殊处理
while((n = read(fd, buf, sizeof(buf))) > 0)
{
ret = send(cfd, buf, n, 0);
if(ret == -1)
{
//要分情况来进行判断,否则会出现资源暂时不能使用的情况
printf("errno = %d\n", errno);
if(errno == EAGAIN)
{
printf("errno:EAGAIN!\n");
continue;
}
else if(errno == EINTR)
{
printf("errno:EINTR!\n");
continue;
}
else
{
perror("send to client err!");
exit(1);
}
}
}
5.4 浏览器请求ico
- 浏览器在请求图片的同时,会请求一个ico图标,用于浏览器
标签文字部分前端的小图标显示。图标文件的名称固定:favicon.ico,放置于服务器提供给浏览器访问的目标目录。
5.5 目录搜索函数
-
函数原型:
int scandir(const char *dirp, struct dirent ***namelist, int (*filter)(const struct dirent *), int (*compar)(const struct dirent **, const struct dirent **)); //默认的排序方式,分别是字母序和版本序 int alphasort(const struct dirent **a, const struct dirent **b); int versionsort(const struct dirent **a, const struct dirent **b);
-
功能:递归遍历目录
-
参数:
dirp:待访问的目录名称
struct dirent:
struct dirent { ino_t d_ino; /* inode number */ off_t d_off; /* not an offset; see NOTES */ unsigned short d_reclen; /* length of this record */ unsigned char d_type; /* type of file; not supported by all filesystem types */ char d_name[256]; /* filename */ };
filter:过滤器,通常情况下可以为NULL
compar:通常情况下位alphasort
-
返回值:
正确:dirent数组中的元素数量
错误:-1,设置errno
-
5.6 汉字的编解码
- 访问带有汉字的文件时,将这个URL复制到对应的浏览器地址栏中,可以看到它对应的在浏览器中的编码
- 命令行采用unicode指令可查看汉字对应的unicode编码。
- 访问带有汉字的文件时候,应该对服务器回发的时候进行编码操作,在浏览器请求资源目录的汉字文件时进行解码操作。
5.7 telnet调试
-
可以使用telnet指令,借助ip和端口号,模拟浏览器的行为,在终端中对访问的服务器进行调试,方便查看服务器回发给浏览器的http协议数据。
-
telnet 127.0.0.1 9876 //回车 GET /hello.c http/1.1 //手动输入请求头,回车