2.协议设计和解析
协议
在计算机中,协议是指一组规则和约定,用于在不同的计算机系统之间进行通信和数据交换。计算机协议定义了数据传输的格式、顺序、错误检测和纠正方法,以及参与通信的各个实体的角色和责任。计算机协议可以在各种不同的层次上操作,包括物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。以下是一些常见的计算机协议:
- 传输层协议:例如TCP (Transmission Control Protocol) 和UDP (User Datagram Protocol),用于在网络上可靠地传输数据。
- 网络层协议:例如IP (Internet Protocol),负责在网络上寻址和路由数据包。
- 应用层协议:例如HTTP (Hypertext Transfer Protocol)、FTP (File Transfer Protocol)、SMTP (Simple Mail Transfer Protocol) 等,用于支持特定的应用程序和服务。
- 数据链路层协议:例如Ethernet、PPP (Point-to-Point Protocol) 等,用于在物理网络之间传输数据帧。
2.1.redis协议
Redis 使用一种简单而有效的文本协议进行通信,这种协议被称为 RESP(REdis Serialization Protocol)。RESP 是一种二进制安全的协议,它可以将多种类型的数据结构序列化为字节流进行传输,并且允许客户端和服务器之间进行高效的通信。
下面是 RESP 协议的一些基本规则:
- 简单字符串(Simple Strings):以 “+” 开头,后面跟着字符串内容和回车换行符 “\r\n”。例如:
+OK\r\n
表示一个成功的响应。- 错误消息(Errors):以 “-” 开头,后面跟着错误消息内容和回车换行符 “\r\n”。例如:
-ERR unknown command 'foobar'\r\n
表示一个错误的响应。- 整数(Integers):以 “:” 开头,后面跟着整数内容和回车换行符 “\r\n”。例如:
:1000\r\n
表示整数 1000。- 批量字符串(Bulk Strings):以 “$” 开头,后面跟着字符串的长度(以字节为单位)、字符串内容和回车换行符 “\r\n”。例如:
$6\r\nfoobar\r\n
表示一个长度为 6 的字符串 “foobar”。- 数组(Arrays):以 “*” 开头,后面跟着数组的长度和数组的元素,每个元素都可以是任意 RESP 类型。例如:
*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n
表示一个包含两个元素的数组,分别是字符串 “foo” 和字符串 “bar”。在实际的通信中,客户端发送命令给 Redis 服务器,并等待服务器的响应。客户端发送的命令遵循 RESP 协议的格式,而服务器返回的响应也是 RESP 格式的。
这种简单而灵活的 RESP 协议使得 Redis 能够高效地处理各种数据类型和命令,并在性能和易用性之间找到了平衡。
代码
package com.hrfan.java_se_base.netty.protocol;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LoggingHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.invoke.MethodHandles;
import java.nio.charset.Charset;
/**
* @author 13723
* @version 1.0
* 2024/3/3 0:03
*/
public class TestRedisProtocol {
private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
public static void main(String[] args) {
// 测试redis协议
NioEventLoopGroup worker = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.channel(NioSocketChannel.class);
bootstrap.group(worker);
bootstrap.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel channel) throws Exception {
channel.pipeline().addLast(new LoggingHandler());
channel.pipeline().addLast(new ChannelInboundHandlerAdapter() {
/**
* 连接一旦建立就发送命令
* @param ctx
* @throws Exception
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// 如果redis 有密码 需要先发送一个auth命令
//
// 发送 AUTH 命令进行认证
// String authCommand = "*2\r\n$4\r\nauth\r\n$5\r\n12345\r\n";