这是我参与11月更文挑战的第27天,活动详情查看:2021最后一次更文挑战
TCP/IP 中消息传输基于流的方式,没有边界,而协议的目的就是划定消息的边界,制定通信双方要共同遵守的通信规则
Redis协议
如果我们要向Redis服务器发送一条set name Nyima
的指令,需要遵守如下协议
1 | swift复制代码// 该指令一共有3部分,每条指令之后都要添加回车与换行符 |
下面是客户端代码
1 | java复制代码public class RedisClient { |
控制台输出结果:
之后服务端接到了发送的数据包后就能够根据协议进行解析内容
HTTP协议
HTTP协议在请求行请求头中都有很多的内容,自己实现较为困难,可以使用HttpServerCodec
作为服务器端的解码器与编码器,来处理HTTP请求
1 | scala复制代码// HttpServerCodec 中既有请求的解码器 HttpRequestDecoder 又有响应的编码器 HttpResponseEncoder |
使用这个方法可以发现会解析出两种类型的消息:请求行请求头、请求体
tips: 可以使用ch.pipeline().addLast(new SimpleChannelInboundHandler())指定单对一种类型的消息感兴趣,这个是只对HttpRequest感兴趣
下面是服务器代码, 服务器负责处理请求并响应浏览器。所以只需要处理HTTP请求即可
1 | java复制代码public class HttpServer { |
浏览器结果:
控制台结果:
自定义协议
除了上面两种协议,我们自己也可以使用netty定义自己的协议
组成要素
- 魔数:用来在第一时间判定接收的数据是否为无效数据包
- 版本号:可以支持协议的升级
- 序列化算法
:消息正文到底采用哪种序列化反序列化方式
+ 如:json、protobuf、hessian、jdk
- 指令类型:是登录、注册、单聊、群聊… 跟业务相关
- 请求序号:为了双工通信,提供异步能力
- 正文长度
- 消息正文
编码器解码器
- 编码器与解码器方法源于父类ByteToMessageCodec,通过该类可以自定义编码器与解码器,泛型类型为被编码与被解码的类。==此处使用了自定义类Message,代表消息==
1 | scala复制代码public class MessageCodec extends ByteToMessageCodec<Message> |
- 编码器负责将附加信息与正文信息写入到ByteBuf中,其中附加信息总字节数最好为2n,不足需要补齐。==正文内容如果为对象,需要通过序列化将其放入到ByteBuf中==
- 解码器负责将ByteBuf中的信息取出,并放入List中,该List用于将信息传递给下一个handler
1 | java复制代码public class MessageCodec extends ByteToMessageCodec<Message> { |
编写测试类
- 测试类中用到了LengthFieldBasedFrameDecoder,避免粘包半包问题
- 通过MessageCodec的encode方法将附加信息与正文写入到ByteBuf中,通过channel执行入站操作。入站时会调用decode方法进行解码
1 | java复制代码public class TestCodec { |
结果:
本文转载自: 掘金