遇事不决,可问春风,春风不语,遵循己心。
序列化和反序列化
序列化和反序列化是计算机科学中常见的概念,它们通常用于将数据结构转换为可存储、传输或重建的格式。这两个过程在许多应用中都起着重要作用,特别是在数据存储、网络通信和编程中。其中序列化是将数据结构(通常是对象、变量或数据)转换为一种线性格式的过程,以便将其存储在文件、数据库或通过网络传输,这个线性格式可以是二进制、JSON、XML等。序列化的主要目的是将数据转换为一种通用格式,以便它可以被传输或存储,并在需要时还原成原始数据结构。
例如,将一个包含学生信息的对象序列化为JSON字符串,以便将其保存到文件或通过网络传输。
反序列化是将序列化后的数据重新转换为原始数据结构的过程。它是序列化的逆过程,反序列化的主要目的是从序列化数据中还原原始数据,以便程序可以使用它进行各种操作。例如,从存储在文件中的JSON字符串中反序列化出学生信息的对象,以便在程序中操作这些信息。例如在网络通信中,序列化将数据转换为可传输的格式,然后在接收端进行反序列化以还原数据。在数据存储中,将对象序列化为文件或数据库中的字段,以便以后检索和使用。
网络协议与序列化、反序列化的关系
在网络通信中,数据通常需要在不同的计算机之间传输,这些数据可以是对象、结构体、文本或其他形式的信息。在传输数据之前,数据需要被转换为字节流或其他可传输的格式,序列化就可以将这些数据转换为二进制或文本表示,使其能够在网络上传输。而网络协议是一组规则和约定,用于在计算机网络中进行通信。常见的网络协议包括HTTP、TCP、UDP等,这些协议规定了数据如何打包、发送、接收和解析。不同的网络协议有不同的数据格式和规范。
因此在网络通信中,数据需要按照特定的协议进行序列化,以满足协议规定的数据格式要求。序列化的过程将数据转换为符合协议要求的格式,通常是字节流或JSON/XML等。序列化后的数据可以通过网络协议传输到目标计算机,而目标计算机可以使用相同的协议进行反序列化,将接收到的数据转换回原始格式,以便进行处理和解析。
总之,序列化和反序列化是在网络通信中将数据转换为适合网络协议传输的格式的关键步骤。网络协议定义了数据的传输规则和格式,而序列化和反序列化则负责将数据与这些规则和格式相匹配,以确保数据能够在网络上正确传输和解析,也可以说协议是负责定制规则,而序列化和反序列化负责执行。
HTTP协议
在应用层上我们可以自己定制协议,但是自定义协议需要自己负责实施和维护,以及确保安全性和互操作性,并且有一定的局限性,成本较大。因此通常建议在可能的情况下使用标准协议,以减少复杂性和提高可维护性。HTTP(Hypertext Transfer Protocol)就是一种现成的, 又非常好用的用于传输超文本的应用层协议,它是万维网的数据通信的基础。且HTTP是一个无状态的协议,这意味着每个请求都是独立的,服务器不会在两个请求之间保持任何数据(状态)。
URL
URL是Uniform Resource Locator(统一资源定位符)的缩写,它是用于标识和定位互联网上资源的地址。URL是Web上的常见术语,它用于指定资源的位置以及如何访问该资源。一个URL通常包括以下几个部分:
-
协议:这部分指定了要使用的协议,例如我们的HTTP、HTTPS、FTP等。
-
主机名:这部分指定了资源所托管的服务器的域名或IP地址。
-
端口:可选部分,指定了服务器上用于访问资源的端口号。如果未指定,默认端口号将根据协议确定,例如HTTP的默认端口是80。
-
路径:这部分指定了服务器上资源的位置,通常是一个文件或目录的路径。路径以斜杠“/”分隔各个部分。
-
查询参数:可选部分,包括键值对,用于向服务器传递额外的参数,参数之间使用“&”符号分隔。
-
片段标识符:可选部分,用于指定资源中的特定片段或位置。
如下一个示例URL:
https://www.example.com:8080/path/to/resource?param1=value1¶m2=value2#section1
其中协议是HTTPS,主机名是www.example.com,端口是8080,路径是/path/to/resource,查询参数包括param1和param2,片段标识符为section1。这个URL可以帮助浏览器或其他客户端定位并访问特定的Web资源。
编码与解码
在处理URL编码和解码时一般可以使用urlencode和urldecode函数,这两个函数通常在编程中用于处理URL中的特殊字符,以确保它们在互联网上传输和处理时不会引发问题。这些函数通常在编程语言的标准库中提供,以帮助开发者处理URL中的特殊字符。urlencode这个函数用于将字符串中的特殊字符编码为URL安全的形式。这包括将空格转换为"%20"、将问号转换为"%3F"、将斜杠转换为"%2F"等。编码后的字符串可以作为URL的一部分传递,并且不会破坏URL的语法,在大多数编程语言中,这个函数通常称为urlencode,encodeURIComponent或类似的名字。
相反urldecode这个函数用于将URL编码的字符串解码回原始形式,还原其中的特殊字符。解码后的字符串可以用于进一步处理或显示给用户。在大多数编程语言中,这个函数通常称为urldecode,decodeURIComponent或类似的名字。
例如可以在一些在线转码网站上查看效果
HTTP协议格式
HTTP消息有两种主要格式,分别为请求消息和响应消息。
HTTP请求消息格式:
格式 | 意义 |
---|---|
请求行 | 包括请求方法、请求的URL和HTTP协议的版本,它们之间由空格分隔。 |
请求头 | 包括一系列的键值对,用于传递请求的元数据信息,如主机、用户代理、接受的内容类型等。 |
空行 | 一个空行用于分隔请求头和请求正文。 |
请求正文 | 可选部分,包含请求的数据。这通常在POST请求中使用。 |
HTTP响应消息格式:
格式 | 意义 |
---|---|
状态行 | 包括HTTP协议的版本、状态码和状态消息,它们之间由空格分隔。 |
响应头 | 包括一系列的键值对,用于传递响应的元数据信息,如内容类型、日期、服务器信息等。 |
空行 | 一个空行用于分隔响应头和响应正文。 |
响应正文 | 包含响应的数据,如HTML页面、JSON数据等。 |
总之,HTTP请求消息和响应消息都遵循这个基本格式,其中状态行或请求行指示请求类型或响应状态,头部包含元数据信息,而正文包含实际的数据。HTTP协议版本(如HTTP/1.1)和状态码(如200 OK)告诉协议的版本和请求或响应的状态。请求方法(如GET、POST)指示请求的类型,而响应的状态码指示响应的状态。HTTPHeader包含有关消息的其他信息,如数据类型、日期和服务器信息,正文包含实际的内容或数据。
HTTP请求处理方法
HTTP为在客户端和服务器之间传输数据,它定义了一组不同的方法(也称为HTTP方法或HTTP动词),用于指定请求的类型和服务器对请求的处理方式。以下是常见的HTTP方法:
方法 | 作用 |
---|---|
GET | 用于请求从服务器获取数据,通常是获取资源(如网页、图像、文档等)。GET请求通常不会对服务器状态产生影响。 |
POST | 用于向服务器提交数据,通常用于创建新资源、提交表单数据或进行处理操作。POST请求可能对服务器状态产生影响。 |
PUT | 用于向服务器发送数据以更新指定的资源。通常用于替代现有资源或创建新资源,如果资源不存在。PUT请求是幂等的,即多次执行相同的请求不会产生不同的结果。 |
DELETE | 用于请求服务器删除指定的资源。 |
PATCH | 用于对资源进行部分更新。与PUT不同,PATCH请求通常用于只更新资源的一部分。 |
HEAD | 类似于GET请求,但不返回请求的实际数据,只返回响应头信息。通常用于获取资源的元数据,如大小或修改日期,而不传输整个资源的内容。 |
OPTIONS | 用于获取服务器支持的HTTP方法列表,或查询资源的通信选项。 |
TRACE | 用于在请求-响应链上执行一个诊断操作,通常用于调试目的。 |
CONNECT | 通常用于将客户端与代理服务器建立透明的TCP/IP连接,通常用于HTTPS代理。 |
这些HTTP方法是HTTP/1.1协议的核心部分,每种方法都具有特定的语义和用途。不同的方法用于不同的操作,以便在Web应用程序中进行资源的获取、创建、更新和删除等操作。
但其实我们最常用的也就GET方法和POST方法。😃
HTTP状态码
HTTP状态码是服务器向客户端提供的3位数字代码,用于表示请求的处理结果。这些状态码通常包含在HTTP响应的头部,以指示请求是否成功,出现了错误,需要重定向等。以下是一些常见的HTTP状态码:
- 1xx - 信息性状态码(Informational)
100 Continue:服务器已接收部分请求,客户端应继续发送其余部分。
101 Switching Protocols:客户端请求协议切换,服务器已经接受并将切换到新协议。 - 2xx - 成功状态码(Successful)
200 OK:请求成功,服务器返回请求的数据。
201 Created:请求成功,并且服务器创建了新资源。
204 No Content:请求成功,但响应不包含实体主体内容。 - 3xx - 重定向状态码(Redirection)
301 Moved Permanently:资源被永久移动到新位置。
302 Found (或者 307 Temporary Redirect):资源被临时移动到新位置。
304 Not Modified:客户端可以使用缓存的版本,因为资源未被修改。 - 4xx - 客户端错误状态码(Client Errors)
400 Bad Request:请求无效或无法理解。
401 Unauthorized:未经授权,需要提供身份验证信息。
403 Forbidden:请求被服务器拒绝。
404 Not Found:请求的资源未找到。 - 5xx - 服务器错误状态码(Server Errors)
500 Internal Server Error:服务器遇到错误。
502 Bad Gateway:作为网关或代理的服务器从上游服务器接收到无效响应。
503 Service Unavailable:服务器暂时无法处理请求,通常是因为过载或维护。
504 Gateway Timeout:作为网关或代理的服务器未能及时从上游服务器获取响应。
这些状态码有助于客户端了解请求的结果,以便采取适当的操作。并且不同的状态码具有不同的含义和语义,可以帮助开发者和用户理解请求的处理情况。
HTTP常见Header
HTTP标头(Header)是包含在HTTP请求和响应中的元数据信息,用于传输有关请求或响应的信息,它们用于传递各种信息,包括内容类型、授权信息、缓存控制、安全性等,常见的字段如下:
-
Accept:指定客户端可接受的响应媒体类型,用于内容协商。
-
Content-Type:指定请求或响应中的媒体类型(如HTML、JSON、XML等)。
-
Authorization:包含用于身份验证的凭据,如用户名和密码、令牌等。
-
User-Agent:包含发出请求的用户代理的信息,通常是浏览器或应用程序的标识。
-
Host:指定请求的目标主机和端口,用于虚拟主机支持。
-
Cookie:包含客户端传递给服务器的Cookie信息,以便服务器保持会话状态。
-
Set-Cookie:服务器在响应中发送的Cookie信息,用于在客户端存储会话信息。
-
Location:通常在3xx重定向响应中使用,指定新的资源位置。
-
Referer(也写作"Referrer"):包含包含当前请求的来源页面的URL。
-
User-Agent:包含发出请求的用户代理的信息,通常是浏览器或应用程序的标识。
-
ETag:与资源相关的实体标签,用于条件请求。
-
Content-Length:指定请求或响应主体的字节数。
HTTP标头的种类众多,可以根据需要进行自定义。它们对于控制请求和响应的处理非常重要,用于实现各种功能和机制,如身份验证、缓存、语言偏好、安全性等,不同的HTTP标头有不同的目的和语义,以满足各种需求。
超简单HTTP服务器
我们可以直接实现一个非常简单的HTTP服务器,当用户访问的时候直接返回一个"hello world",客户端网页上就会输出 “hello world”,如下代码是一个使用C++标准库的示例。
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <stdexcept>
#include <netinet/in.h>
#include <unistd.h>
void handleClient(int clientSocket)
{
std::string response = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n";
response += "hello world";
send(clientSocket, response.c_str(), response.size(), 0);
close(clientSocket);
}
int main()
{
int serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket < 0)
{
std::cerr << "Error opening socket" << std::endl;
return 1;
}
struct sockaddr_in serverAddress;
serverAddress.sin_family = AF_INET;
serverAddress.sin_addr.s_addr = INADDR_ANY;
serverAddress.sin_port = htons(8080); // You can use a different port if needed
if (bind(serverSocket, (struct sockaddr *)&serverAddress, sizeof(serverAddress)) < 0)
{
std::cerr << "Error binding to port" << std::endl;
return 1;
}
if (listen(serverSocket, 5) < 0)
{
std::cerr << "Error listening" << std::endl;
return 1;
}
std::cout << "Server is listening on port 8080..." << std::endl;
while (true)
{
struct sockaddr_in clientAddress;
socklen_t clientAddressLength = sizeof(clientAddress);
int clientSocket = accept(serverSocket, (struct sockaddr *)&clientAddress, &clientAddressLength);
if (clientSocket < 0)
{
std::cerr << "Error accepting client connection" << std::endl;
}
char buffer[1024 * 10] = {0};
ssize_t read_size = read(clientSocket, buffer, sizeof(buffer) - 1);
if (read_size < 0)
{
return 1;
}
printf("[Request] %s", buffer);
handleClient(clientSocket);
}
close(serverSocket);
return 0;
}
当使用浏览器访问的时候,页面直接输出“hello world”,同时服务器打印出客户端发出的请求信息。
下面的GET /favicon.ico HTTP/1.1 HTTP请求是浏览器自动发出的,用于尝试获取网站的图标,通常是网站的图标文件,以便在浏览器的标签页和书签中显示。
GET 是HTTP请求方法,/favicon.ico 是请求的URL路径,它是一个相对路径,通常指向网站根目录下的favicon.ico文件。网站通常在其根目录下放置一个名为favicon.ico的图标文件,以便浏览器可以获取并显示该图标。这个图标通常显示在浏览器的标签页和书签中,用于标识网站。如果服务器上存在favicon.ico文件,浏览器会尝试获取它,以便显示在用户界面中。
虽然/favicon.ico请求是相对常见的,但并不是所有网站都使用相同的文件名或位置来存储它们的网站图标。有时,网站管理员可以通过在HTML文档的部分使用标签来指定不同的图标文件,以提供多个图标选项。
总结
文章对序列化和反序列化的概念以及意义进行了介绍,同时就网络协议和序列化、反序列化的关系进行了分析,总结出协议是负责定制规则,序列化和反序列化负责实现规则。文章还重点对应用层协议HTTP进行重点介绍,对HTTP的协议格式、请求处理方法、状态码和报头等进行分析,最后实现了一个简单的HTTP服务器对客户端发出的请求进行观察。
码文不易,如果文章对你有帮助的话劳烦点一个👍支持一下作者,持续更新中…