虽然我们说,应用层协议是我们程序猿自己定的
但实际上,已经有大佬们定义了一些现成的,又非常好用的应用层协议,供我们直接参考使用,http(超文本传输协议)就是其中之一
目录
- 认识url
- urlencode和urldecode
- http协议格式
- 实现服务器
- 测试
1. 认识URL
平时我们俗称的“网址”其实就是说的URL,称为统一资源定位系统,所有网络上的资源,都可以用唯一的一个“字符串”标识,并且可以获取到
我们知道了访问一个主机需要ip地址和端口号,平时访问网页都是用的域名。比如http:: //www.baidu,com,这个域名域名解析后就有了ip地址,比较出名的一些ip地址是浏览器内置的
ping百度,可以查出ip地址,用ip地址可以直接访问
一般端口号都默认为80,可以省略。会自动加上http前缀
网络行为分为两种:
1.把别人的东西拿下来
2.把自己的东西
2. urlencode和urldecode
在url里,有/?:等很多特殊字符作为分隔,这些字符不能随意出现
如果某个参数中正好带了这些字符,会发生什么情况
用百度举例,搜索内容里含特殊字符
https://www.baidu.com/s?wd=aa%2F%3F%3A%3A&rsv_spt=1&rsv_iqid=0xd3cae3dd00085542&issp=1&f=8&rsv_bp=1&rsv_idx=2&ie=utf-8&tn=monline_3_dg&rsv_dl=tb&rsv_enter=1&rsv_sug3=9&rsv_sug1=7&rsv_sug7=100&rsv_t=7ecdzhBC0Bh5dMgagm%2F7yuCN6CDzw5ybYluxs0zOYnD2W8MH0ly6oMisE%2FE0%2BA9%2Fx5bR&rsv_sug2=0&rsv_btype=t&inputT=11571&rsv_sug4=15488
aa后面的内容变成了其他内容,所以浏览器会对特殊字符做处理,规则如下:
将需要转码的字符转为16进制,然后从右到左,取4位(不足4位直接处理),每2位做一位,前面加上%,编码成%XY格式。
关于转换,一般是浏览器自己完成,不需要手动实现。如果需要实现,网上也有很多源码,也有在线解析工具
urlcode工具
3. http协议格式
请求
整体请求都是一行一行的内容,\n或\r\n分割。首先是请求行,空格分隔,请求方法,url,http版本,有时候更新全部都更新的,所以版本信息要互相核对。
请求报头由很多的key:value格式组成,请求报头之后考虑到每行内容用\n分割,所以要区别正文用一部分空行分开。就可以保证读到完整的报头,报头中有一个key存了正文的长度,保证了读到完整的正文
响应
响应和请求格式差不多。状态行包含状态码和解释,无论正确和错误都要响应,让用户知道具体错误的原因
响应例子
telnet连接百度,发送GET请求根目录
首行: [方法] + [url] + [版本]
Header:请求的属性,冒号分割的键值对,每组属性之间用\n分割,遇到空行表示Header结束
Body:空行后面的内容都是Body,Bodey允许为空字符串,入股存在,则在Header会有一个Content-Length属性标识Body长度
首行: [版本号] + [状态码] + [状态码]
Header:请求的属性,冒号分割的键值对,每组属性之间用\n分割,遇到空行表示Header结束
Body:空行后面的内容都是Body,Bodey允许为空字符串,入股存在,则在Header会有一个Content-Length属性标识Body长度
fiddler抓包
本来是客户发给服务端,fiddler作为代理要通过它发送和接收数据,就可以抓到了
postman提交请求
4. 实现服务器
先照例实现tcp服务端,用上一节封装的sock文件,接收连接请求,收到连接请求后创建线程提供服务。传入的ThreadData包含接收会话创建的sockfd
线程函数分离调用网页服务函数
处理函数读取内容,假设读取到了完整的报文,然后生成响应格式发送
先创建每块内容然后放到一个字符串里,每一行换行符分隔
响应行:空格分隔,版本号,响应码,解释
正文:helloworld的字符串
报头:只包含一条正文长度就行,key是content-length,然后计算正文长度拼到后面
空行:\r\n
用新字符串变量将上面的内容按顺序添加进去,发送给客户端
5. 测试
浏览器用ip+端口访问,会显示字符串