socket通讯粘包问题

最近在学习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...");
	}
}



下面是一个简单的 C# Socket 通讯解决粘包的示例: ```csharp using System; using System.Net; using System.Net.Sockets; using System.Text; public class SocketServer { private Socket listener; private const int BUFFER_SIZE = 1024; private byte[] buffer = new byte[BUFFER_SIZE]; public void Start() { listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); listener.Bind(new IPEndPoint(IPAddress.Any, 8080)); listener.Listen(10); Console.WriteLine("Server started on port 8080."); while (true) { Socket client = listener.Accept(); Console.WriteLine("Client connected: " + client.RemoteEndPoint.ToString()); // Start receiving data from client client.BeginReceive(buffer, 0, BUFFER_SIZE, 0, new AsyncCallback(OnReceive), client); } } private void OnReceive(IAsyncResult ar) { Socket client = (Socket)ar.AsyncState; int bytesRead = client.EndReceive(ar); if (bytesRead > 0) { // Convert received bytes to string string receivedData = Encoding.UTF8.GetString(buffer, 0, bytesRead); // Process received data Console.WriteLine("Received data: " + receivedData); // Continue receiving data from client client.BeginReceive(buffer, 0, BUFFER_SIZE, 0, new AsyncCallback(OnReceive), client); } else { // Client has disconnected Console.WriteLine("Client disconnected: " + client.RemoteEndPoint.ToString()); client.Close(); } } } public class SocketClient { private Socket client; private const int BUFFER_SIZE = 1024; private byte[] buffer = new byte[BUFFER_SIZE]; public void Connect() { client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); client.BeginConnect(new IPEndPoint(IPAddress.Loopback, 8080), new AsyncCallback(OnConnect), null); } private void OnConnect(IAsyncResult ar) { Console.WriteLine("Connected to server."); client.EndConnect(ar); // Start receiving data from server client.BeginReceive(buffer, 0, BUFFER_SIZE, 0, new AsyncCallback(OnReceive), client); } private void OnReceive(IAsyncResult ar) { Socket client = (Socket)ar.AsyncState; int bytesRead = client.EndReceive(ar); if (bytesRead > 0) { // Convert received bytes to string string receivedData = Encoding.UTF8.GetString(buffer, 0, bytesRead); // Process received data Console.WriteLine("Received data: " + receivedData); // Continue receiving data from server client.BeginReceive(buffer, 0, BUFFER_SIZE, 0, new AsyncCallback(OnReceive), client); } else { // Server has disconnected Console.WriteLine("Server disconnected."); client.Close(); } } public void Send(string data) { byte[] sendData = Encoding.UTF8.GetBytes(data); client.BeginSend(sendData, 0, sendData.Length, 0, new AsyncCallback(OnSend), null); } private void OnSend(IAsyncResult ar) { client.EndSend(ar); } } class Program { static void Main(string[] args) { // Start server SocketServer server = new SocketServer(); server.Start(); // Connect client to server SocketClient client = new SocketClient(); client.Connect(); // Send data to server client.Send("Hello, server!"); Console.ReadLine(); } } ``` 这个示例中,我们使用了异步的 BeginReceive 和 BeginSend 方法来在接收和发送数据时不阻塞主线程。在接收数据时,我们先接收到一部分数据,然后判断是否收到了完整的数据,如果没有就继续接收。在发送数据时,我们将要发送的数据转换成字节数组后,使用 BeginSend 方法发送,然后在回调函数中调用 EndSend 方法结束发送。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值