http协议是前人已经定义好的一种现成的应用层协议,使用http协议时,我们无需考虑序列化、协议细节等问题。在深入了解http协议之前,先回顾一下应用层协议所包含的内容。
目录
一、应用层协议包含的内容
实际的应用层协议包含了这么几个内容,每一部分的内容正好对应了网络七层模型中的某一层模型:
(1) 建立连接 —— 通信的基本(会话层)
(2) 协议细节 —— 通信双方约定好数据传递的格式,结构体 or 字符串(应用层)
(3) 序列化和反序列化 —— 为了便于数据传输所进行的数据格式转换(表示层)
整合上述内容就是,A 和 B要进行通信,第一步是建立连接,这是通信的基本。第二步,为了让通信双方能正常通信,双方要约定好数据传递的格式,不要闹出“一方传字符串,另一方却想着准备接收结构体类型”的笑话。第三步,将发送方的数据类型转化为适合网络传输的数据类型,比如结构体类型不便于网络传输。
二、http协议的请求/响应格式(协议细节)
http协议是应用层协议的一种,必然也包含了上述的内容。我们需要关注的是协议细节、序列化这两方面的问题。协议细节代表通信双方约定好要传递的数据格式,下面要说的请求格式和响应格式就是http协议的协议细节。
1、http的请求格式
http的请求格式如下,最多包含四个部分,也可以是三个部分,因为正文部分有可能不存在。在后续的代码测试中可以看到实际请求。这里只是先做简单介绍。
2、http的响应格式
http的响应格式类似于请求格式,不同之处主要在于状态行包含的信息、响应正文返回的信息。
三、服务端接收/响应http请求
1、服务端接收http请求
这里就使用先前写好的TCP服务端来接收http请求,发送方就是我们的浏览器,我们只需要在浏览器中输入 “服务器的ip地址:端口号” ,浏览器就会自动帮我们构建请求发送给服务端。
注意:下面这种写法仅适用于测试,因为测试的时候,只会发送一个请求。实际上使用recv来接收http请求是不大合适的,因为服务器在某个时刻可能会收到多个请求,按字节读取的话,有可能会出现某个请求读取到一半的时候,接收缓冲区大小不够了,于是就不读了。这显然不是我们希望看到的。
测试截图如下:
2、服务端构建响应
(1) 构建响应测试
现在服务端要对接收到的请求做出响应,http响应的构成以行为单位,因为是测试,下面就按照上面画的图的顺序来。
std::string http_state = "http/1.0 200 OK\n"; //状态行
std::string http_header = "Content-Type: text/plain\n"; //响应报头(响应正文的类型是文本)
http_header += "xxx: xxx";
std::string empty_row = "\n"; //空行
std::string http_text = "hello, world..."; //响应正文
std::string http_response = http_state + //构建http响应
http_header +
empty_row +
http_text;
send(sock,http_response.c_str(),http_response.size(),0); //发送响应
测试截图如下:
上述代码是放在成功接收到浏览器的请求之后,测试的时候需要先给服务端发送请求才能看到服务端对请求做出的响应。
(2) 序列化说明
前面只提到了协议细节,上述过程是否存在序列化呢?存在的,只不过不明显罢了。
序列化的时候,是以行为单位,将多个字符串拼接起来,这就构成了我们所谓请求或者响应。
反序列化的时候,由于是以行为单位,必然存在换行符 '\n',我们可以根据换行符来取出不同行的内容。