您的位置:首页 > 其它

socket通讯粘包问题

2016-04-22 16:35 302 查看
最近在学习netty框架,在学习java nio的时候会遇到socket粘包问题,这里贴出代码,共同学习。

这里解决粘包的方法是(长度+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...");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: