面试题01
// websocket的协议体
/**
* WebSocket协议使用HTTP握手,建立WebSocket连接后,数据传输就由HTTP协议切换为独立的WebSocket协议。
*协议体结构如下:
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
*+-+-+-+-+-------+-+-------------+-------------------------------+
*|F|R|R|R| opcode|M| Payload len | Extended payload length |
*|I|S|S|S| (4) |A| (7) | (16/64) |
*|N|V|V|V| |S| | (if payload len==126/127) |
*| |1|2|3| |K| | |
*+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
*| Extended payload length continued, if payload len == 127 |
*+ - - - - - - - - - - - - - - - +-------------------------------+
*| Payload Data continued ... |
*+---------------------------------------------------------------+
*各字段意义如下:
*- FIN: 1bit,表示报文是否为最后一帧。
*- RSV1-RSV3: 各1bit,为扩展使用。
*- Opcode: 4bit,定义报文类型,如0x1表示文本报文,0x2表示二进制报文。
*- MASK: 1bit,表示Payload Data是否进行了掩码处理。客户端发出的报文为1,服务器发出的为0。
*- Payload len: 7bit / 7+16bit / 7+64bit,表示有效载荷长度。
*- Masking-key: 4字节,如果MASK为1,则该字段存在。用于解密Payload Data。
*- Payload data: 有效载荷数据,由Opcode定义类型,长度由Payload len指定。
*- Frame length: 报文总长度 = 2 + Payload len + 4(如果MASK = 1)
*所以,WebSocket的协议体,从结构上主要包含是否位最后一帧、扩展位、报文类型、载荷长度、掩码密钥(如果有)和载荷数据等内容。服务器和客户端通过这些字段来解析WebSocket报文,进行通信
*/
// 断点续传的原理
/* 断点续传的原理是:当文件传输中断后,继续从中断点开始传输,而不是重新开始传输整个文件。
实现断点续传需要解决几个关键问题:
1. 记录中断点位置。传输文件前,需要记录文件总大小和已传输的大小,中断时记录已经传输的位置,以便续传使用。
2. 恢复到中断点。续传时,需要将文件指针定位到中断点位置,接着读取文件并传输。
3. 校验继续传输的文件内容。续传时,需要验证从中断点开始后续的内容是否与源文件相同,防止文件在两次传输中间被修改。常用的方法是记录源文件内容的hash或checksum值。
一个简单的断点续传实现逻辑如下:
1. 记录源文件总大小file_size和已传大小transferred。
2. 计算源文件内容的hash值,记录为file_hash。
3. 上传文件,当传输中断后,记录中断点位置为position。
4. 续传时,将文件指针定位到position,读取后续内容。
5. 计算从position读取的内容hash值为content_hash。
6. 判断content_hash与file_hash是否相同。如果不同,表示文件被修改,重新开始上传。
7. 如果相同,将transferred的值更新为position,并从position继续上传。
8. 上传完成后,判断transferred值是否等于file_size,确认是否全部上传完成。
该原理较简单直接。在实际应用中,我们还需要考虑断点信息的持久化存储,以 handle 网络异常中断等情况。也可以使用更复杂的校验机制,如基于分块的hash,而不仅校验续传内容。但核心原理仍是记录断点位置,验证续传内容完整性,并从中断点继续传输。
综上,断点续传的关键在于智能地记录和管理传输的状态与进度。通过这些信息,我们可以将非正常中断的大文件传输,有效拼接成完整的文件,提供更好的用户体验。相比于重新开始整个上传,断点续传机制更高效和智能
*/
// HTTP的断点续传
/* HTTP协议支持断点续传,主要是通过两个字段来实现:
1. Range字段。客户端在请求时,通过Range指定需要请求的内容范围,格式为:
Range: bytes=开始位置-结束位置
例如,请求前100个字节,Range为:Range: bytes=0-99
2. Content-Range字段。服务器在响应中通过Content-Range指定返回内容的范围及总长度,格式为:
Content-Range: bytes 开始位置-结束位置/文件总大小
例如,返回前100个字节,Content-Range为:Content-Range: bytes 0-99/1024
基于Range字段,HTTP的断点续传实现流程如下:
1. 客户端第一次请求文件,服务器正常返回整个文件内容。客户端记录接收到的最后一个字节位置last_byte_pos。
2. 如果网络中断,客户端发现未接收完整文件。在再次请求时,通过Range字段指定从last_byte_pos+1的位置开始请求。
3. 服务器接收到带Range字段的请求后,通过Content-Range在响应中指定返回内容的范围。并从last_byte_pos+1开始读取文件内容返回。
4. 客户端接收到服务器响应后,将last_byte_pos更新为本次接收的最后一个字节位置。
5. 客户端继续发送Range请求,服务器继续返回对应范围内容,直到整个文件传输完成。
6. 如果 Range 请求范围不合法,服务器会返回416 Range Not Satisfiable 的响应。
7. 完成了整个文件的续传后,服务器在响应体中会返回200 OK,而不是206 Partial Content。这标记着续传过程的结束。
所以,HTTP实现断点续传,是通过Range / Content-Range字段指定请求和返回的内容范围来达到续传效果。客户端需要持续记录已接收内容的最后字节位置,以便下次发送恢复请求。而服务器需要支持Range的处理,才能正确续传文件内容。
相比FTP等其他协议,HTTP的断点续传更为灵活和便捷。对于大文件分块传输,提高网络利用率和传输速度,实现更好的用户体验,HTTP断点续传机制发挥着重要作用
*/
// HTTP的header,request,response
/* HTTP报文分为请求报文(request)和响应报文(response)两种。它们都包含两部分:
1. 首部(Header):描述报文相关的元信息,包括方法、 url、协议版本、内容长度、 cookie 等。
2. 主体(Body):包含请求或者响应的内容信息,可以是网页内容、文件、图片等。
请求行包含请求方法、URL、HTTP版本
请求首部包含Host、User-Agent、Content-Type等信息。主体可选,包含POST请求提交的数据。
HTTP响应报文:
状态行包含HTTP版本、状态码、原因短语,如:
HTTP/1.1 200 OK
响应首部包含Content-Type、Content-Length、Set-Cookie等信息。主体包含响应内容,如网页HTML源码、图片、视频等。
常见的HTTP请求方法有:
- GET:请求获取资源
- POST:请求提交资源
- PUT:请求更新资源
- DELETE:请求删除资源
常见的HTTP状态码有:
- 200:请求成功
- 301:资源已永久移动
- 404:未找到资源
- 500:服务器内部错误
所以,HTTP报文通过请求/响应行定义报文类型、协议及状态。通过首部提供报文元信息。通过可选的主体包含资源内容。这些元素共同定义了HTTP的基本交互过程和机制
*/
// content-type,content-length
/* Content-Type和Content-Length都是HTTP首部字段,它们的作用分别是:
Content-Type:定义实体主体的MIME类型和编码格式。
格式为:Content-Type: MIME类型; 参数=值
例如:
Content-Type: text/html; charset=utf-8
Content-Type: image/png
Content-Type: application/json
常见的MIME类型有:
- text/html: HTML格式
- text/plain:纯文本格式
- image/png:PNG图片
- image/jpeg:JPG图片
- application/json:JSON格式
- application/xml:XML格式 等等
Content-Length:定义实体主体的长度,即字节数。
格式为:Content-Length: 字节数
例如:Content-Length: 2048
Content-Type和Content-Length的作用是告知客户端实体主体的类型、编码、长度等信息。这样客户端在接收实体主体前,就可以根据这些元信息来决定如何处理主体内容,例如:
- 根据Content-Type选择解析器解析内容
- 根据Content-Length读取完整主体内容
- 预留Content-Length指定的缓存空间等
如果没有这两个首部,客户端将无法预知主体内容的具体格式和长度,无法正确解析和处理主体。
所以,Content-Type和Content-Length作为主体相关的重要元信息首部,在HTTP协议中发挥着关键作用。服务端在返回响应报文时,应当根据主体内容正确添加这两个首部。同样,客户端在接收响应报文时,也需要根据这两个首部正确解析和处理主体内容。
综上,Content-Type定义主体类型,Content-Length定义主体长度。它们为请求和响应的主体提供格式与长度信息,使得内容可以正确编码、传输与解析。这是HTTP作为应用层协议,成功交换和处理数据信息的关键所在
*/
// redis设计,key应该怎么设置
/* 在Redis中设置key时,需要考虑以下几个方面:
1. 业务相关性:key应该跟所存储的数据有一定的业务关联性,便于理解和管理。例如可以设置为用户ID,商品ID加其他修饰词等。
2. 鉴权考虑:如果Redis被多个系统或应用使用,key应该包含系统/应用身份信息,用于鉴权和区分数据所有权。
3. Hash tag:对于非字符串的key,可以使用{}包裹,以便Redis正确识别。例如key可以是user:{uid}形式。
4. 简洁性:key应该尽可能简洁,避免过长的key。可以采用一定的分隔规则或缩略表示法。
5. 全局唯一:对于需要全局唯一的key,可以使用namespace加唯一ID的方式。例如app1:{uid},app2:{tid}。
6. 过期策略:如果key需要设置过期时间,应该在key上做一定的标记,便于查找和管理。例如:app1:{uid}:1m 代表1分钟后过期。
7. 前缀法:可以为不同类型的数据设置不同的前缀,用于区分。例如:user:列表、 tweet:微博内容、product:商品等。
除此之外,也要考虑key的命名问题,例如:
- 避免使用{}和()等特殊字符(如果不是 must 的话)
- 不要使用空格,可以使用-或_分隔
- 同义词使用一致的命名,不能混用
- 数字不要单独出现在首位
- 尽量使用连词线连接而非下划线
综上,Redis key的设计需要考虑业务相关性、鉴权、简洁性、全局唯一性和过期策略等方面。合理的key可以使Redis更易管理和维护。确保鉴权、避免过期不当删除等也关乎系统安全。
另外,key的命名规则也需要一定的约定,让所有使用Redis的系统和工程师可以一致理解,这样可以增强可读性并避免一些问题。所以,Redis key的设计既是技术考量,也有管理与协作的因素,系统设计者和开发者都应在意。
*/