定义一个通用的接口: public interface IPackageContenParser { public int getProtocolHeadLength(); public int getProtocolBodyLength(byte[] head); /**获取一个完整包的长度*/ public int getCompletePackageLength(byte[] recvUnhandledPkg); /**从socket收到的数据包中截取一个完整包*/ public byte[] getCompletePackage(byte[] recvUnhandledPkg); /**从已通过粘包处理的完整包中获取数据段*/ public byte[] getDataSegment(byte[] handledPkg); } SOcket接收处: private final void loopAndHandlePackage(final IPackageContenParser parser) throws IOException { int bytesRead = -1; /**remains保存解析出完整包后剩余的部分*/ byte[] remains = EmptyContainer.EMPTY_BYTE_ARRAY; while (!stopReceive) { try { while ((bytesRead = in.read(buffer)) != -1) { byte[] temp = new byte[bytesRead]; System.arraycopy(buffer, 0, temp, 0, bytesRead); if(remains.length > 0) { /**剩余部分的长度大于0,代表有上一次处理后,还有剩余部分未处理,那么把收到的包和这个半包合并成一个新包(上一次包的数据在前) * 第一次执行时,由于remains长度为0,因此跳过了这个判断内的语句,而后解析第一个包,若是有剩余就组合 * */ temp = PackageTools.combinePackage(remains, temp); } remains = handlePackage(temp, parser); } } catch (IOException e) { if("socket closed".equalsIgnoreCase(e.getMessage())){ //关闭时,由于read方法还在阻塞中,因此要抛出这个异常,这是正常的,因此不处理 } else { e.printStackTrace(); } } Sleeper.sleepSomeMilliseconds(50); } } 具体处理粘包方法: /*** * 解析从服务器收到的包,切割完整包,并返回半包 * @param unHandledPkg 从socket收到的数据包 * @param parser 不一样的协议,传递不一样的包内容解析器 * @return 若是收到的包是一个或者多个完整包,那么返回0长度字节数组 * 若是收到的包是1个半或者N个半数据包,那么截取一个或N个完整包,并把剩余的部分返回 */ private final byte[] handlePackage(byte[] unHandledPkg, IPackageContenParser parser) { /**调用一次read,从Server收到的数据包(多是半包、1个包、1.x、2.x....)*/ int pkgLen = unHandledPkg.length; /**一个完整数据包的长度*/ int completePkgLen = parser.getCompletePackageLength(unHandledPkg); if(completePkgLen > pkgLen) { /**当前收到的数据不到一个完整包,则直接返回,等待下一个包*/ return unHandledPkg; } else if (completePkgLen == pkgLen) { /**一个完整包,则直接丢到已处理队列*/ handledQueue.offer(unHandledPkg); return EmptyContainer.EMPTY_BYTE_ARRAY; } else { /**有多个包,那么就递归解析,*/ byte[] onePkg = parser.getCompletePackage(unHandledPkg); handledQueue.offer(onePkg); /**截取除完整包后的剩余部分*/ byte[] remain = PackageTools.getSubBytes(unHandledPkg, onePkg.length, pkgLen - onePkg.length); return handlePackage(remain, parser); } } public class EmptyContainer { public static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; @SuppressWarnings("rawtypes") public static final Map EMPTY_MAP = new HashMap(0); @SuppressWarnings("rawtypes") public static final List EMPTY_LIST = new ArrayList(0); }