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

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]

总结:

    主要是对于多线程问题出现数据问题的处理。粘包和拆包,多线程下数据的传输等问题。
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值