TCP-IP学习笔记七:Netty使用--简单通信编程3

来源:互联网 发布:各编程语言比较 编辑:程序博客网 时间:2024/05/31 18:39

TCP/IP学习笔记七:Netty使用–简单通信编程3

标签(空格分隔): Netty 网络编程


TCP-IP学习笔记五:Netty使用–简单通信编程1

TCP-IP学习笔记六:Netty使用–简单通信编程2

对于上个程序,对对象类型的传输,发送单个数据没有任何问题,运行很正常,当我们一次发送多个请求(包含多个对象)还是这样正常?会出现什么问题?
对客户端【IO事件处理类】代码进行修改:

    /**     * 发送请求     */    @Override    public void channelActive(ChannelHandlerContext ctx) throws Exception {        for (int i = 0; i < 5; i++) {            ctx.writeAndFlush(new User(i, "guozh"+i));        }    }

运行结果:

服务器端:    服务器监听8989端口    解码····    客户端发请求了···服务器接收的数据:User [id=0, name=guozh0]    编码····客户端:    编码····    编码····    编码····    编码····    编码····    解码····    客户端接收的响应:User [id=0, name=guozh0]

为什么会出现客户端发送多次请求,而服务器端只收了一次请求和返回一次响应呢?了解TCP/IP协议的可能知道为什么,因为出现了TCP粘包/拆包现象。

TCP粘包/拆包

    TCP是一个“流”协议,就是没有界限的一串数据。大家可以想想河里的流水,他们汇成一片,没有分界线。TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完成的包可能会被TCP拆分成多个包进行发送,也可能把多个小包封装成一个大数据包发送,这就是TCP粘包和拆包问题。

参考:Netty权威指南第四章

如图所示:

这里写图片描述

如何解决粘包/拆包问题?

服务器端【注册IO事件类】代码:

package com.netty.demo3.server;import com.netty.demo2.ObjectCodec;import io.netty.channel.ChannelInitializer;import io.netty.channel.socket.SocketChannel;import io.netty.handler.codec.LengthFieldBasedFrameDecoder;import io.netty.handler.codec.LengthFieldPrepender;public class ServerChannelInitializer extends ChannelInitializer<SocketChannel> {    /**     * 注册IO事件处理类     */    @Override    protected void initChannel(SocketChannel ch) throws Exception {        //添加的长度        ch.pipeline().addLast(new LengthFieldPrepender(2));        /*         * maxFrameLength   最大的长度         * lengthFieldOffset    从那开始         * lengthFieldLength    读入长度         * lengthAdjustment              * initialBytesToStrip  截取几个字节         */        ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(65535, 0, 2, 0, 2));        ch.pipeline().addLast(new ObjectCodec());        ch.pipeline().addLast(new ServerRequestResponseHander());    }}

客户端【注册IO事件类】代码:

package com.netty.demo3.client;import com.netty.demo2.ObjectCodec;import io.netty.channel.ChannelInitializer;import io.netty.channel.socket.SocketChannel;import io.netty.handler.codec.LengthFieldBasedFrameDecoder;import io.netty.handler.codec.LengthFieldPrepender;public class ClientChannelInitializer extends ChannelInitializer<SocketChannel> {    /**     * 注册IO事件处理类     */    @Override    protected void initChannel(SocketChannel ch) throws Exception {        ch.pipeline().addLast(new LengthFieldPrepender(2));        ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(65535, 0, 2, 0, 2));        ch.pipeline().addLast(new ObjectCodec());        ch.pipeline().addLast(new ClientRequestResponseHander());    }}

其他类不做修改。

Netty给我们提供了两个方法:LengthFieldBasedFrameDecoder和LengthFieldPrepender多粘包/拆包的支持。详细介绍参考:Netty权威指南第七章
这里写图片描述
执行结果:

服务器:    服务器监听8989端口    解码····    客户端发请求了···服务器接收的数据:User [id=0, name=guozh0]    编码····    解码····    客户端发请求了···服务器接收的数据:User [id=1, name=guozh1]    编码····    解码····    客户端发请求了···服务器接收的数据:User [id=2, name=guozh2]    编码····    解码····    客户端发请求了···服务器接收的数据:User [id=3, name=guozh3]    编码····    解码····    客户端发请求了···服务器接收的数据:User [id=4, name=guozh4]    编码····客户端:    编码····    编码····    编码····    编码····    编码····    解码····    客户端接收的响应:User [id=0, name=guozh0]    解码····    客户端接收的响应:User [id=1, name=guozh1]    解码····    客户端接收的响应:User [id=2, name=guozh2]    解码····    客户端接收的响应:User [id=3, name=guozh3]    解码····    客户端接收的响应:User [id=4, name=guozh4]

总结:

    主要是对于多线程问题出现数据问题的处理。粘包和拆包,多线程下数据的传输等问题。
0 0
原创粉丝点击