客户端:根据 长度+数据 方式发送

package com.server;

import java.net.Socket;
import java.nio.ByteBuffer; public class Client { public static void main(String[] args) throws Exception {
Socket socket = new Socket("127.0.0.1", 10101); String message = "hello"; byte[] bytes = message.getBytes(); ByteBuffer buffer = ByteBuffer.allocate(4 + bytes.length);
buffer.putInt(bytes.length);//netty是write,ByteBuffer是nio的,所以用put。
buffer.put(bytes); byte[] array = buffer.array(); for(int i=0; i<5; i++){
socket.getOutputStream().write(array);
} socket.close();
} }

服务端:根据 长度+数据 接收解码

package com.server;

import java.net.InetSocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder; public class Server { public static void main(String[] args) {
//服务类
ServerBootstrap bootstrap = new ServerBootstrap();
//boss线程监听端口,worker线程负责数据读写
ExecutorService boss = Executors.newCachedThreadPool();
ExecutorService worker = Executors.newCachedThreadPool();
//设置niosocket工厂
bootstrap.setFactory(new NioServerSocketChannelFactory(boss, worker));
//设置管道的工厂
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
@Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("decoder", new MyDecoder());
pipeline.addLast("handler1", new HelloHandler());
return pipeline;
}
});
bootstrap.bind(new InetSocketAddress(10101));
System.out.println("start!!!");
}
}
package com.server;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.frame.FrameDecoder; public class MyDecoder extends FrameDecoder {
@Override //FrameDecoder的decode方法
protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {
//buffer是netty的ChannelBuffer
if(buffer.readableBytes() > 4){ //必须大于基本的最短长度4个字节
if(buffer.readableBytes() > 2048){ //防止socket攻击,缓存很大,所以限制数据的长度不能大于2048,
buffer.skipBytes(buffer.readableBytes());
}
//标记
buffer.markReaderIndex();
//长度
int length = buffer.readInt();
//buffer里面剩余的数据小于长度
if(buffer.readableBytes() < length){
//前面做了标记,这里可以还原
buffer.resetReaderIndex();
//缓存当前剩余的buffer数据,等待剩下数据包到来
return null;
}
//大于长度,开始读数据
byte[] bytes = new byte[length];
buffer.readBytes(bytes);
//往下传递对象给HelloHandler,这次的buffer处理完了,后面在来buffer的时候FrameDecoder会帮我们循环读取,
return new String(bytes);
}
//缓存当前剩余的buffer数据,等待剩下数据包到来(FrameDecoder帮我们实现的),
return null;
}
}
package com.server;

import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler; public class HelloHandler extends SimpleChannelHandler { private int count = 1;//单线程的没有并发问题 @Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
System.out.println(e.getMessage() + " " +count);
count++;
}
}
2、看下粘包和分包是怎么样一个情况:

粘包是因为服务端和客户端没有约定好数据结构,发送100个hello,粘包就是100个hello全在一起服务端分不开。分包就是服务端把100个hello随机的分开。

定义一个稳定的结构:最简单结构:length + hello
根据长度+数据会有攻击:
,把长度定义的很大Intger.max,这种数据包,会导致一直在缓存,把缓存撑的很大。通常被称为socket攻击,字节流式攻击。
所以要 包头+长度+数据,前面加包头做标识。大于2048就清除,然后读取到包头就表示数据的开始。 心中会有连个疑惑(FrameDecoder源码分析):
1、为什么FrameDecoder return的对象就是往下传递的对象 (还是调用了sendUpstream)
2、buffer里面数据未被读取完怎么办? (cumulation缓存)
3、为什么return null就可以缓存buffer (cumulation缓存)
3、FrameDecoder里面的cumulation其实就是一个缓存的buffer对象 public abstract class FrameDecoder extends SimpleChannelUpstreamHandler //事件进入管道以后进入第一个handler的messageReceived方法,
protected ChannelBuffer cumulation;//缓存的buffer对象
@Override
public void messageReceived(
ChannelHandlerContext ctx, MessageEvent e) throws Exception {
Object m = e.getMessage();
if (!(m instanceof ChannelBuffer)) {//判断是不是一个ChannelBuffer,不是就不管他了,
ctx.sendUpstream(e);//传给下一个handler
return;
}
ChannelBuffer input = (ChannelBuffer) m;//是ChannelBuffer,转成ChannelBuffer对象
if (!input.readable()) {//没有数据读,也不管了。return
return;
}
if (cumulation == null) {//如果renturn null还有数据,就缓存在buffer里面
try {
// the cumulation buffer is not created yet so just pass the input to callDecode(...) method
callDecode(ctx, e.getChannel(), input, e.getRemoteAddress());
} finally {
updateCumulation(ctx, input);
}
} else {
input = appendToCumulation(input);
try {
callDecode(ctx, e.getChannel(), input, e.getRemoteAddress());
} finally {
updateCumulation(ctx, input);
}
}
}

netty10---分包粘包的更多相关文章

  1. TCP网络通讯如何解决分包粘包问题(有模拟代码)

    TCP作为常用的网络传输协议,数据流解析是网络应用开发人员永远绕不开的一个问题. TCP数据传输是以无边界的数据流传输形式,所谓无边界是指数据发送端发送的字节数,在数据接收端接受时并不一定等于发送的字 ...

  2. TCP粘包拆包问题

    阿π 专注于网络协议,系统底层,服务器软件 C++博客 | 首页 | 发新随笔 | 发新文章 | | | 管理 Socket粘包问题 这两天看csdn有一些关于socket粘包,socket缓冲区设置 ...

  3. netty解决粘包半包问题

    前言:开发者用到TCP/IP交互时,偶尔会遇到粘包或者半包的数据,这种情况有时会对我们的程序造成严重的影响,netty框架为解决这种问题提供了若干框架 1. LineBasedFrameDecoder ...

  4. socket的半包,粘包与分包的问题

    http://zhaohuiopensource.iteye.com/blog/1541270 首先看两个概念: 短连接: 连接->传输数据->关闭连接    HTTP是无状态的,浏览器和 ...

  5. 【转载】socket的半包,粘包与分包的问题

    http://zhaohuiopensource.iteye.com/blog/1541270 首先看两个概念: 短连接: 连接->传输数据->关闭连接    HTTP是无状态的,浏览器和 ...

  6. Netty之粘包分包

    粘包现象 客户端在一个for循环内连续发送1000个hello给Netty服务器端, Socket socket = new Socket("127.0.0.1", 10101); ...

  7. HP-Socket快速入门:分包、粘包解析

    环境配置 vs2015 windows7 64位 hp-socket 5.0 安装hp-socket 新建控制台项目TelnetServer,打开Nuget管理工具,搜索hp-socket: 安装成功 ...

  8. Python网络编程,粘包、分包问题的解决

    tcp编程中的粘包.分包问题的解决: 参考:https://blog.csdn.net/yannanxiu/article/details/52096465 服务端: #!/bin/env pytho ...

  9. 【Python】TCP Socket的粘包和分包的处理

    Reference: http://blog.csdn.net/yannanxiu/article/details/52096465 概述 在进行TCP Socket开发时,都需要处理数据包粘包和分包 ...

  10. netty之粘包分包的处理

    1.netty在进行字节数组传输的时候,会出现粘包和分包的情况.当个数据还好,如果数据量很大.并且不间断的发送给服务器,这个时候就会出现粘包和分包的情况. 2.简单来说:channelBuffer在接 ...

随机推荐

  1. VS2008 AddIn 操作DTE2

    在VS2008扩展开发中,最重要的就是DTE对象.DTE对象提供了对扩展性模型中其他对象的访问.DTE是VS自动化模型中的顶级对象. 在按照http://www.cnblogs.com/yjf512/ ...

  2. 《C++ Primer Plus》第4章 学习笔记

    数组.结构和指针是C++的3中符合类型.数组可以在一个数据对象中存储多个同种类型的值.通过使用索引或下标,可以访问数组中各个元素.结构可以将多个不同类型的值存储在同一个数据对象中,可以使用成员关系运算 ...

  3. 动态规划——最长公共上升子序列LCIS

    问题 给定两个序列A和B,序列的子序列是指按照索引逐渐增加的顺序,从原序列中取出若干个数形成的一个子集,若子序列的数值大小是逐渐递增的则为上升子序列,若A和B取出的两个子序列A1和B1是相同的,则A1 ...

  4. Django学习笔记第六篇--实战练习二--简易实现登录注册功能demo

    一.绪论: 简易实现登录功能demo,并没有使用默认身份验证模块,所以做的也很差,关闭了csrf保护,没有认证处理cookie和session,只是简单实现了功能.另外所谓的验证码功能是伪的. 二. ...

  5. java基础之Flex弹性布局、JSP错误处理以及Log4J

    一.Flex弹性布局 1.产生的比较晚,目前在移动网页开发中可以使用,而且逐渐成为主流. 在桌面网页开发中使用的比较少(主要是桌面浏览器的兼容性问题更加严重) 2.开启方法: 在容器标签上加上 dis ...

  6. Servlet------>ServletConfig和ServletContext

    原理图: 之一--------->servletConfig 有些时候,有些参数不适合写死,而且初始化servlet要用,可以通过这个头来调用servletConfig 例如:serlet数据库 ...

  7. No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?

    ... 60 common frames omittedCaused by: java.lang.IllegalStateException: No Feign Client for loadBala ...

  8. HDU5667—Sequence(对数转化)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5667 题目意思:f1=1,i=1 f2=2 ,i=2 fi=a^b*f[i-1]^c*f[i-2] i ...

  9. Oracle Java Mission Control MBean 服务器 飞行记录器

    Oracle Java Mission ControlMBean 服务器飞行记录器

  10. 微信公众号获取用户openId How to use cURL to get jSON data and decode the data?

    w http://stackoverflow.com/questions/16700960/how-to-use-curl-to-get-json-data-and-decode-the-data