socket通讯粘包问题
2016-04-22 16:35
302 查看
最近在学习netty框架,在学习java nio的时候会遇到socket粘包问题,这里贴出代码,共同学习。
这里解决粘包的方法是(长度+4),就是发送头信息的时候增加4个字节,通过这4个字节来判断是否粘包,然后再进行拆包
客户端代码:
最后服务器端通信的代码:
package com.cg.socket.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.StringEncoder;
import com.cg.socket.client.MyDecoder;
import com.cg.socket.client.ServerHandler;
/**
* @author Chalmers 2016年2月24日 下午2:21:33
*/
public class Server {
public static void main(String[] args) {
ServerBootstrap serverBootstrap = new ServerBootstrap();
ExecutorService boss = Executors.newCachedThreadPool();
ExecutorService worker = Executors.newCachedThreadPool();
serverBootstrap.setFactory(new NioServerSocketChannelFactory(boss,worker));
serverBootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("decoder", new MyDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", new ServerHandler());
return pipeline;
}
});
serverBootstrap.bind(new InetSocketAddress(9090));
System.out.println("start...");
}
}
这里解决粘包的方法是(长度+4),就是发送头信息的时候增加4个字节,通过这4个字节来判断是否粘包,然后再进行拆包
客户端代码:
package com.cg.socket.client; import java.io.IOException; import java.net.Socket; import java.net.UnknownHostException; import java.nio.ByteBuffer; /** * @author Chalmers 2016年2月24日 下午2:35:39 */ public class Client { public static void main(String[] args) throws UnknownHostException, IOException { Socket socket = new Socket("127.0.0.1", 9090); String message = "hello"; byte[] bytes = message.getBytes(); // 设置空间大小为一个存储了长度的int型数据(长度)加上转换后的byte数组 ByteBuffer buffer = ByteBuffer.allocate(4 + bytes.length); // 将长度存入 buffer.putInt(bytes.length); // 将数据存入 buffer.put(bytes); // 转换成字节数组 byte[] array = buffer.array(); // 向服务端发送1000次 for (int i = 0; i < 1000; i++) { socket.getOutputStream().write(array); } // 关闭 socket.close(); } }
package com.cg.socket.client; 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; /** * @author Chalmers 2016年2月24日 下午2:23:49 */ public class MyDecoder extends FrameDecoder { @Override protected Object decode(ChannelHandlerContext chc, Channel channel, ChannelBuffer buffer) throws Exception { // 如果buffer中的可读字节大于4个(即除了长度以外还有数据,因为长度可能是为0的) if (buffer.readableBytes() > 4) { // 标记,指向当前指针位置,读取数据时使用 buffer.markReaderIndex(); // 取得长度 int len = buffer.readInt(); // 如果剩余可读字节小于长度的话,则表明发生了拆包现象,那么不对它进行处理 if (buffer.readableBytes() < len) { // 重置标记 buffer.resetReaderIndex(); // 返回null,表示等待 return null; } // 对数据进行处理 byte[] bytes = new byte[len]; buffer.readBytes(bytes); // 将数据返回到ServerHandler中进行处理 return new String(bytes); } return null; } }
ServerHandler类中的代码
</pre><pre name="code" class="java">package com.cg.socket.client; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; /** * @author Chalmers 2016年2月24日 下午2:22:41 */ public class ServerHandler extends SimpleChannelHandler { int count = 1; @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { // 对从MyDecoder中传递过来的数据进行处理 System.out.println((String) e.getMessage() + " " + count); count++; } }
最后服务器端通信的代码:
package com.cg.socket.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.StringEncoder;
import com.cg.socket.client.MyDecoder;
import com.cg.socket.client.ServerHandler;
/**
* @author Chalmers 2016年2月24日 下午2:21:33
*/
public class Server {
public static void main(String[] args) {
ServerBootstrap serverBootstrap = new ServerBootstrap();
ExecutorService boss = Executors.newCachedThreadPool();
ExecutorService worker = Executors.newCachedThreadPool();
serverBootstrap.setFactory(new NioServerSocketChannelFactory(boss,worker));
serverBootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("decoder", new MyDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", new ServerHandler());
return pipeline;
}
});
serverBootstrap.bind(new InetSocketAddress(9090));
System.out.println("start...");
}
}
相关文章推荐
- 周杰伦、范冰冰、陈冠希、刘涛……为何对直播无法自拔
- HDU 4493 Tutor(四舍五入 模拟)
- C# Action<T>
- MFC-双缓冲绘图-CMemDC的封装
- C++技巧
- CRC16(modbus)校验
- 【初识MyBatis→简单的mybatis开发环境搭建】
- 移动端 触摸事件 ontouchstart、ontouchmove、ontouchend、ontouchcancel
- Object窥探
- 仿人人客户端的滑动效果
- hdu 1175 连连看 搜索—dfs
- 学生宿舍分配方案优化
- 2016/04/22 ①文件概述 ② 文件操作
- 首页调取二级、三级栏目
- PopupWindow
- 爬楼梯 js算法
- JQuery前端操作JSON
- apr和aprutil的安装
- codeforces 655D (构造)
- C++004进阶