以下是例子:
服务端:
package com.zy.callrecord.socket;
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 MyServerSocket {
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 = 3;//包头长度
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长度的字节子数组作为报文长度,你懂得;要对应编码gbk是2,utf8是3
byte[] temp = new byte[0];
temp = mergebyte(temp, bytes, 0, PACKET_HEAD_LENGTH);
String templength = new String(temp,"UTF8");
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,"UTF8"));
bytes = new byte[0];
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
以下是客户端:
package com.zy.callrecord.socket;
import java.io.*;
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!流量的点点滴滴的嘎嘎嘎我们中国来来来";
String reqMessage2="2012年11月7日 - Java Socket TCP粘包和拆包问题 服务端读取这次消息,可能由于socket缓冲区较大,继续等待客户端的发送,如果未收到则读取完成,如果收到则将新读取的内...";
String reqMessage3="{\n" +
" \"employees\": [\n" +
" {\n" +
" \"firstName\": \"Bill\",\n" +
" \"lastName\": \"Gates\"\n" +
" },\n" +
" {\n" +
" \"firstName\": \"George\",\n" +
" \"lastName\": \"Bush\"\n" +
" },\n" +
" {\n" +
" \"firstName\": \"Thomas\",\n" +
" \"lastName\": \"Carter\"\n" +
" }\n" +
" ]\n" +
"}";
for (int i = 0; i < 100; i++) {
try {
sendPacket(reqMessage);
sendPacket(reqMessage2);
sendPacket(reqMessage3);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void sendPacket(String message) throws UnsupportedEncodingException {
byte[] contentBytes = message.getBytes("UTF8");// 包体内容,如果不指名是utf8编码的话就是默认gbk,那就是一个汉字代表2个字节,utf8是一个汉字3个字节
int contentlength = contentBytes.length;// 包体长度
String head = String.valueOf(contentlength);// 头部内容
byte[] headbytes = head.getBytes("UTF8");// 头部内容字节数组
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();
}
}
}
}
运行结果:
说明:
注意点:注意编码,因为包含中文所以用utf8编码;而utf8编码是一个汉字3个字节;如果不知道编码是gbk,gbk是一个汉字代表2个字节而且又写汉字不识别;
以上如有不对请指正;因为对socket也是一知半解