java socket解决半包、粘包问题

java socket解决半包、粘包问题

一、java socket出现半包、粘包问题原因及解决见博客:
二、java socket半包、粘包问题解决方案
1、以特殊字符串比如/r、/n作为数据的结尾,这样就可以区分数据包了。
2、发送请求包的时候只发送固定长度的数据包,这样在服务端接收数据也只接收固定长度的数据,这种方法效率太低,不太合适频繁的数据包请求。
3、在tcp协议的基础上封装一层数据请求协议,既数据包=数据包长度+数据包内容,这样在服务端就可以知道每个数据包的长度,也就可以解决半包、粘包问题
三、java socket半包、粘包问题重现,代码如下
package org.weir.socket.socketPackage;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class SocketTest {
	public static void main(String[] args) throws IOException, InterruptedException{
		new SocketServer().start();
		new SocketClient().start();
	}
	
	static class SocketClient extends Thread{
		Socket clientSocket = new Socket();
		public SocketClient() throws IOException{
			clientSocket.connect(new InetSocketAddress(8089));
		}
		public void run(){
			String reqMessage = "HelloWorld! from clientsocket this is test half packages!";
			try {
				for( int i=0;i<10;i++){
					OutputStream os = clientSocket.getOutputStream();
					os.write(reqMessage.getBytes());
					System.out.println("send message "+i+" "+reqMessage);
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}finally{
				if (clientSocket != null) {
					try {
						clientSocket.close();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
			
		}
	}
	
	static class SocketServer extends Thread{
		ServerSocket serverSocket;
		public SocketServer(){
			try {
				serverSocket = new ServerSocket();
				serverSocket.bind(new InetSocketAddress(8089));
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		public void run(){
			int count = 0;
			Socket socket = null;
			try {
				socket = serverSocket.accept();
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			while(true){
				try {
					byte[] byteBuffer = new byte[50];
					StringBuffer receivBuffer = new StringBuffer();
					InputStream reader = socket.getInputStream();
					count = reader.read(byteBuffer);
					if(count>0){
						receivBuffer.append(new String(byteBuffer,0,count));
						System.out.println("receive data from client:"+receivBuffer.toString());
					}
					count = 0;
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
执行结果如下:

一共发送了10个包,因为接收的缓冲区是50个字节,所以会出现无法接收到一个完整包的情况,也即出现半包与粘包的情况。
四、java socket解决半包、粘包的问题。
package org.weir.socket.socketPackage;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
/**
 * socket解决半包问题  采用包体长度(两字节)+包体内容来拆包
 * @author weir
 * 2017年9月19日下午4:31:36
 */
public class ClientSocket {
	public static void main(String args[]) throws IOException {
		Socket clientSocket = new Socket();
		clientSocket.connect(new InetSocketAddress(8089));
		new SendThread(clientSocket).start();

	}

	static class SendThread extends Thread {
		Socket socket;
		PrintWriter printWriter = null;

		public SendThread(Socket socket) {
			this.socket = socket;
			try {
				printWriter = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		@Override
		public void run() {
			String reqMessage = "HelloWorld! from clientsocket this is test half packages!";
			for (int i = 0; i < 100; i++) {
				sendPacket(reqMessage);
			}
			if (socket != null) {
				try {
					socket.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}

		}

		public void sendPacket(String message) {
//			byte[] contentBytes = message.getBytes();// 包体内容
//			int contentlength = contentBytes.length;// 包体长度
//			String head = String.valueOf(contentlength);// 头部内容
//			byte[] headbytes = head.getBytes();// 头部内容字节数组
//			byte[] bytes = new byte[headbytes.length + contentlength];// 包=包头+包体
//			int i = 0;
//			for (i = 0; i < headbytes.length; i++) {// 包头
//				bytes[i] = headbytes[i];
//			}
//			for (int j = i, k = 0; k < contentlength; k++, j++) {// 包体
//				bytes[j] = contentBytes[k];
//			}
			try {
				OutputStream writer = socket.getOutputStream();
//				writer.write(bytes);
				writer.write(message.getBytes());
				writer.flush();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

}

package org.weir.socket.socketPackage;

import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
/*
 * packet=packetHead+content
 * 先读出包体长度,再读出包体,不够就一直读
 */
public class SocketServer {
	public static void main(String args[]) {
		ServerSocket serverSocket;
		try {
			serverSocket = new ServerSocket();
			serverSocket.bind(new InetSocketAddress(8089));
			while (true) {
				Socket socket = serverSocket.accept();
				new ReceiveThread(socket).start();

			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	static class ReceiveThread extends Thread {
		public static final int PACKET_HEAD_LENGTH=2;//包头长度
		private Socket socket;
		private volatile byte[] bytes = new byte[0];

		public ReceiveThread(Socket socket) {
			this.socket = socket;
		}

		public byte[] mergebyte(byte[] a, byte[] b, int begin, int end) {
			byte[] add = new byte[a.length + end - begin];
			int i = 0;
			for (i = 0; i < a.length; i++) {
				add[i] = a[i];
			}
			for (int k = begin; k < end; k++, i++) {
				add[i] = b[k];
			}
			return add;
		}

		@Override
		public void run() {
			int count =0;
			while (true) {
				try {
					InputStream reader = socket.getInputStream();
					if (bytes.length < PACKET_HEAD_LENGTH) {
						byte[] head = new byte[PACKET_HEAD_LENGTH - bytes.length];
						int couter = reader.read(head);
						if (couter < 0) {
							continue;
						}
						bytes = mergebyte(bytes, head, 0, couter);
						if (couter < PACKET_HEAD_LENGTH) {
							continue;
						}
					}
					// 下面这个值请注意,一定要取2长度的字节子数组作为报文长度,你懂得
					byte[] temp = new byte[0];
					temp = mergebyte(temp, bytes, 0, PACKET_HEAD_LENGTH);
					String templength = new String(temp);
					int bodylength = Integer.parseInt(templength);//包体长度
					if (bytes.length - PACKET_HEAD_LENGTH < bodylength) {//不够一个包
						byte[] body = new byte[bodylength + PACKET_HEAD_LENGTH - bytes.length];//剩下应该读的字节(凑一个包)
						int couter = reader.read(body);
						if (couter < 0) {
							continue;
						}
						bytes = mergebyte(bytes, body, 0, couter);
						if (couter < body.length) {
							continue;
						}
					}
					byte[] body = new byte[0];
					body = mergebyte(body, bytes, PACKET_HEAD_LENGTH, bytes.length);
					count++;
					System.out.println("server receive body:  " + count+new String(body));
					bytes = new byte[0];
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}
}

结果如下:

client一共发送了100条数据,server端接收到的都是完整的包。
Java中的Socket通信是一种基于网络的通信方式,可以实现进程间的数据交换和通信。下面是一个简单的Java Socket通信的示例代码: ```java // 服务器端 import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) throws IOException { // 创建服务器Socket并绑定端口 ServerSocket serverSocket = new ServerSocket(8888); System.out.println("服务器启动,等待客户端连接..."); // 等待客户端连接 Socket socket = serverSocket.accept(); System.out.println("客户端已连接"); // 获取输入流 InputStream inputStream = socket.getInputStream(); byte[] buffer = new byte[1024]; int length; // 读取客户端发送的数据 while ((length = inputStream.read(buffer)) != -1) { String message = new String(buffer, 0, length); System.out.println("收到客户端消息:" + message); } // 关闭连接 inputStream.close(); socket.close(); serverSocket.close(); } } ``` ```java // 客户端 import java.io.IOException; import java.io.OutputStream; import java.net.Socket; public class Client { public static void main(String[] args) throws IOException { // 创建客户端Socket并指定服务器地址和端口 Socket socket = new Socket("localhost", 8888); // 获取输出流 OutputStream outputStream = socket.getOutputStream(); // 发送消息到服务器 String message = "Hello, Server!"; outputStream.write(message.getBytes()); // 关闭连接 outputStream.close(); socket.close(); } } ``` 以上代码实现了一个简单的Socket通信,服务器端监听指定端口,等待客户端连接,客户端通过指定服务器地址和端口与服务器建立连接,并发送消息给服务器。
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值