前言:最近作安卓端项目须要用到socket和PC端互发指令,可是期间遇到了这么一个现象,就是有时候PC端消息指令发的过快,致使安卓端接收了多条粘在一块儿的指令,这就是粘包现象。java
解析:socket在发送数据的时候会对数据进行粘包和分包处理,这致使咱们须要额外处理,虽然看上去没有必要(麻烦、懒得处理),可是这是socket作的优化。android
什么是粘包?
就是在极短期内发送了几回不多的数据量,正常是接收端应该也一样接收了好几回,可是发送端却把这几回的数据合成一块儿,一次发了过来,几个数据“粘”在了一块儿。git
什么是拆包?
当发送端一次性发送了大量的数据时,socket将数据拆分,按批次发送,数据被“拆”开发送了。github
解决方案:web
一、添加标记
能够在每条指令后面加特殊字符,好比“%#*”,这样多个特殊字符集合,而后接收端按照规定的切分就好了。
二、包头+包体
由于接受的时候是字节,因此在每条消息以前加一个定长的字节数组表明包体的长度。
网上搜了一位大神的,感受挺好的,亲测可用传送门数组
解决实例:(包头+包体)
首先推荐一个很好用的socket框架,内部封装的很好,能够监听链接状态,我是基于这个基础上修改的。传送门框架
package com.hite.communicate.socket; import android.os.Message; import android.util.Log; import com.hite.communicate.CustomMessageConstant; import com.hite.communicate.utils.DataUtils; import com.hite.communicate.utils.EventBusUtil; import com.koushikdutta.async.AsyncServer; import com.koushikdutta.async.AsyncServerSocket; import com.koushikdutta.async.AsyncSocket; import com.koushikdutta.async.ByteBufferList; import com.koushikdutta.async.DataEmitter; import com.koushikdutta.async.Util; import com.koushikdutta.async.callback.CompletedCallback; import com.koushikdutta.async.callback.DataCallback; import com.koushikdutta.async.callback.ListenCallback; import java.net.InetAddress; import java.net.UnknownHostException; public class Server { private InetAddress host; private int port; private AsyncServerSocket asyncServerSocket; private AsyncSocket asyncsocket; private final int HEADER_LENGTH = 4; private byte[] mData; public Server(String host, int port) { try { this.host = InetAddress.getByName(host); this.port = port; setup(); } catch (UnknownHostException e) { throw new RuntimeException(e); } } private void setup() { asyncServerSocket = AsyncServer.getDefault().listen(host, port, new ListenCallback() { @Override public void onAccepted(final AsyncSocket socket) { if(asyncsocket==null) { asyncsocket = socket; handleAccept(socket); } } @Override public void onListening(AsyncServerSocket socket) { } @Override public void onCompleted(Exception ex) { } }); } public void clear() { mData=null; if(asyncsocket!=null) { asyncsocket.end(); asyncsocket.close(); asyncsocket=null; } if(asyncServerSocket!=null) { asyncServerSocket.stop(); } } public void sendToPcMessage(String message) { if(asyncsocket!=null) { Util.writeAll(asyncsocket, DataUtils.getSendMsg(message.getBytes()), new CompletedCallback() { @Override public void onCompleted(Exception ex) { } }); } } private void handleAccept(final AsyncSocket socket) { socket.setDataCallback(new DataCallback() { @Override public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) { byte[] data = bb.getAllByteArray(); if(mData!=null) { receiveMsg(DataUtils.byteMerger(mData,data)); mData=null; } else { receiveMsg(data); } } }); socket.setClosedCallback(new CompletedCallback() { @Override public void onCompleted(Exception ex) { asyncsocket=null; mData=null; } }); socket.setEndCallback(new CompletedCallback() { @Override public void onCompleted(Exception ex) { } }); } private void receiveMsg(byte[] data) { if(data.length>HEADER_LENGTH) { byte[] size = new byte[HEADER_LENGTH]; System.arraycopy(data,0,size,0,HEADER_LENGTH); int bodySize = DataUtils.byteArrayToInt(size); Log.e("threadMode",bodySize+"receiveMsg"); int totalLength = bodySize+HEADER_LENGTH; //不够一个包 if(data.length<totalLength) { mData=data; return; //多于一个包 } else if(data.length>totalLength) { DataUtils.dispatchMsg(data,bodySize); byte[] otherData = new byte[data.length-totalLength]; System.arraycopy(data,totalLength,otherData,0,data.length-totalLength); receiveMsg(otherData); //正好一个包 } else { DataUtils.dispatchMsg(data,bodySize); } } else { mData = data; } } }
package com.hite.communicate.utils; import android.os.Message; import com.hite.communicate.CustomMessageConstant; import java.io.UnsupportedEncodingException; public class DataUtils { //包头+包体 public static byte[] getSendMsg(byte[] src) { byte[] head = intToByteArray(src.length); return byteMerger(head,src); } //字节数组转int public static int byteArrayToInt(byte[] b) { return b[3] & 0xFF | (b[2] & 0xFF) << 8 | (b[1] & 0xFF) << 16 | (b[0] & 0xFF) << 24; } //int转字节数组 public static byte[] intToByteArray(int a) { return new byte[] { (byte) ((a >> 24) & 0xFF), (byte) ((a >> 16) & 0xFF), (byte) ((a >> 8) & 0xFF), (byte) (a & 0xFF) }; } //数组合并 public static byte[] byteMerger(byte[] byte_1, byte[] byte_2){ byte[] byte_3 = new byte[byte_1.length+byte_2.length]; System.arraycopy(byte_1, 0, byte_3, 0, byte_1.length); System.arraycopy(byte_2, 0, byte_3, byte_1.length, byte_2.length); return byte_3; } //拆消息体 public static void dispatchMsg(byte[] data,int bodySize) { byte[] msgByte = new byte[bodySize]; System.arraycopy(data,4,msgByte,0,bodySize); try { Message message = new Message(); message.what= CustomMessageConstant.PC_MESSAGE; message.obj = new String(msgByte,"UTF-8"); EventBusUtil.sendMessage(message); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } }