定義一個通用的接口: 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); }