Android socket 客户端 C++服务端, 延时严重解决,贴点粘包代码

发布时间:2016-12-8 17:56:26 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"Android socket 客户端 C++服务端, 延时严重解决,贴点粘包代码",主要涉及到Android socket 客户端 C++服务端, 延时严重解决,贴点粘包代码方面的内容,对于Android socket 客户端 C++服务端, 延时严重解决,贴点粘包代码感兴趣的同学可以参考一下。

这个问题曾经困扰姐很久,但因为只是延时,而数据仍然正确,就将这个问题放在一边了。 昨天开始研究,以为是IO包没有NIO包快的原因,昨天改用NIO socket,写完一测,仍然有严重的延时呀。 姐差点傻眼,不过还好姐聪明,原来是姐缓存的数据没有全部处理掉呀,而是在等下次有数据进来的时候才处理,那些聊天消息其实早就发来了,被姐藏着呢。 哎,终于轻松了许多。 贴点代码出来现现眼吧 ps : 姐用的是google protobuf协议呦 private int dataState = 0;// 上一次收到消息后得到的状态 (初始时为 0 ) private final int EQUAL = 0;//正好 private final int LACK = 1;//少了 private final int OVER = 2;//多了 private byte[] fromLastBytes; //上次剩余的 private int overLast;// 上次剩余的长度 private byte[] savedBytes;// 不够,保存在lackedBytes里,等待下次传入数据后拼接 private byte[] exactBytes; // 正好的也是最终要处理的 private void handleServerMessage(byte[] temp, int count) { System.out.println("***************接收服务端信息***************** start " + count); // System.out.println("上次信息情况: dataState : " + dataState ); // // if(dataState == OVER)System.out.println("上次信息剩余: overLast : " + overLast); // if(dataState == LACK)System.out.println("上次信息缺少 savedBytes.length : " + savedBytes.length); byte[] bytes = null; if(dataState == EQUAL) // 1:第一次有消息进来 2:本次消息之前 传入及所需相等 { bytes = new byte[count]; for(int i = 0; i < count; i++) { bytes[i] = temp[i]; } }else if (dataState == LACK) {//上次消息不够 : 上次保留的 + 本次传入的 bytes = new byte[savedBytes.length + count]; for(int i = 0; i<savedBytes.length; i++) { bytes[i] = savedBytes[i]; } for(int i = 0; i < count; i++) { bytes[i + savedBytes.length] = temp[i]; } savedBytes = null; }else if (dataState == OVER) {//上次消息有多余 : 上次多余的 + 本次传入的 bytes = new byte[fromLastBytes.length + count]; for(int i = 0 ; i < fromLastBytes.length; i++) { bytes[i] = fromLastBytes[i]; } for(int i = 0; i < count; i++) { bytes[i + fromLastBytes.length] = temp[i]; } fromLastBytes = null; } byte whole_msg_len_bytes[] = new byte[2]; whole_msg_len_bytes[0] = bytes[2]; whole_msg_len_bytes[1] = bytes[3]; short whole_msg_len = StreamTool.byteToShort(whole_msg_len_bytes);// (2) ---> 整条信息长度(3-7) // System.out.println(" 1 + 2 + 信息 需要的长度(3-7) : "+ (whole_msg_len + 4) ); // System.out.println("经过拼接的信息长度 : " + bytes.length); //处理本次 dataState = getDataState(whole_msg_len,bytes.length); // System.out.println("经过拼接后信息情况: dataState : " + dataState); if(dataState == EQUAL ) { exactBytes = new byte[whole_msg_len]; for(int i = 0 ; i< whole_msg_len; i++) { exactBytes[i] = bytes[i + 4]; } handleFinalBytes(exactBytes); } if(dataState == OVER) { exactBytes = new byte[whole_msg_len]; for(int i = 0 ; i< whole_msg_len; i++) { exactBytes[i] = bytes[i + 4]; } handleFinalBytes(exactBytes); overLast = bytes.length - whole_msg_len -4; fromLastBytes = new byte[overLast]; // System.out.println("经过拼接后剩余: overLast : " + overLast); for(int i = 0; i< overLast ; i++) { fromLastBytes[i] = bytes[whole_msg_len+4 +i]; } handleServerMessage(null,0); // 这句就是姐原来的困扰所在噩噩噩噩噩噩噩噩噩 } if (dataState == LACK) { savedBytes = new byte[bytes.length]; savedBytes = bytes.clone(); } } private void handleFinalBytes(byte[] message) { //message 已经去掉flag和标准的长度 ---- 共去掉4bytes byte[] protocol_bytes = new byte[4]; for(int i = 0 ; i < 4; i++) { protocol_bytes[i] = message[i + 74]; } int protocol = StreamTool.bytesToInt(protocol_bytes); System.out.println("NioSocketClient 收到服务端信息协议号: " + protocol); byte[] protobuf_length_bytes = new byte[4]; for(int i = 0 ; i < 4; i++) { protobuf_length_bytes[i] = message[i + 78]; } int protobuf_length = StreamTool.bytesToInt(protobuf_length_bytes); byte[] protobuf_bytes = new byte[protobuf_length]; for(int i = 0 ; i < protobuf_length; i++) { protobuf_bytes[i] = message[i + 82]; } Message respMsg = GetMessageByProtocol.getMessage(protocol, protobuf_bytes); SocketDataEvent socketDataEvent = new SocketDataEvent(this, protocol, respMsg); NioSocketClient.notifyListener(socketDataEvent); } private int getDataState(short whole_msg_len, int count) { int dataState = -1; if(whole_msg_len + 4 == count) dataState = EQUAL; if(whole_msg_len + 4 > count) dataState = LACK; if(whole_msg_len + 4 < count) dataState = OVER; return dataState; } 暂时没出现错误,有错了姐再来改 以上代码有误,参考底下的 import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.IOException; import java.net.Socket; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import com.chat.data.ChatRoomData; import com.chat.data.GetMessageByProtocol; import com.chat.event.SocketDataEvent; import com.chat.event.SocketDataEventListener; import com.google.protobuf.Message; import com.utils.StreamTool; public class MySocket { DataInputStream dataInputStream; BufferedOutputStream bufferedOutputStream; Socket socket; public static List<SocketDataEventListener> listeners = new ArrayList<SocketDataEventListener>(); static MySocket instance; public static boolean flag; public static MySocket getInstance() { if (instance == null) { instance = new MySocket(); } return instance; } public void connectMySocket(String ip, int port) { try { socket = new Socket(ip, port); flag = true; dataInputStream = new DataInputStream(socket.getInputStream()); bufferedOutputStream = new BufferedOutputStream( socket.getOutputStream()); new MyNewSocketReader(dataInputStream).start(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public void closeMySocket() { try { flag = false; bufferedOutputStream.close(); dataInputStream.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } } public void addSocketDataEventListener(SocketDataEventListener listener) { listeners.add(listener); } public void removeSocketDataEventListener(SocketDataEventListener listener) { listeners.remove(listener); } public void sendMessage(byte[] msg, int protocol) { int msgSize = msg.length; // (9)'s length // int bufferlen = msgSize + 86; // (1) ~ (9)total length int len = msgSize + 82; // (3) ~ (9) total length try { bufferedOutputStream.write(StreamTool.shortToByte((short) 0xEA)); bufferedOutputStream.write(StreamTool.shortToByte((short) len)); byte uuid[] = (ChatRoomData.uuid.toString()).getBytes("UTF-8"); bufferedOutputStream.write(uuid); int leftSize = 64 - uuid.length; for (int i = 0; i < leftSize; i++) { bufferedOutputStream.write(0); } bufferedOutputStream.write(StreamTool.intToByte(4)); bufferedOutputStream.write(StreamTool.intToByte(5)); bufferedOutputStream.write(StreamTool.shortToByte((short) 6)); bufferedOutputStream.write(StreamTool.intToByte(protocol)); bufferedOutputStream.write(StreamTool.intToByte(msgSize)); bufferedOutputStream.write(msg); bufferedOutputStream.flush(); } catch (IOException e) { e.printStackTrace(); } } public static void notifyListener(SocketDataEvent socketDataEvent) { for (int i = 0; i < MySocket.listeners.size(); i++) { MySocket.listeners.get(i).socketDataEvent(socketDataEvent); } } } class MyNewSocketReader extends Thread { private int dataState = 0; private final int EQUAL = 0; private final int LACK = 1; private final int OVER = 2; private byte[] exactBytes; private byte[] bufferBytes; DataInputStream dataInputStream; public MyNewSocketReader(DataInputStream dis) { this.dataInputStream = dis; } @Override public void run() { while (MySocket.flag) { recvMsg(dataInputStream); } } private void recvMsg(DataInputStream inputStream) { try { if (inputStream.available() != 0) { byte input[] = new byte[inputStream.available()]; int count = inputStream.read(input); if (count > -1) { addToBufferBytes(input); input = null; } } } catch (IOException e) { e.printStackTrace(); } catch (NegativeArraySizeException e) { e.printStackTrace(); } catch (NullPointerException e) { e.printStackTrace(); } } private void addToBufferBytes(byte[] fromServer) { if(bufferBytes == null || bufferBytes.length == 0) bufferBytes = fromServer.clone(); else { byte[] temp = bufferBytes.clone(); bufferBytes = new byte[temp.length + fromServer.length]; for(int i = 0 ; i < temp.length; i++) { bufferBytes[i] = temp[i]; } for(int i = 0; i< fromServer.length;i++) { bufferBytes[i + temp.length] = fromServer[i]; } } handleBytesFromServer(); } private void handleBytesFromServer() { byte whole_msg_len_bytes[] = new byte[2]; whole_msg_len_bytes[0] = bufferBytes[2]; whole_msg_len_bytes[1] = bufferBytes[3]; short whole_msg_len = StreamTool.byteToShort(whole_msg_len_bytes);// (2) ---> 整条信息长度(3-7) dataState = getDataState(whole_msg_len,bufferBytes.length); if(dataState == EQUAL ) { exactBytes = new byte[whole_msg_len]; for(int i = 0 ; i< whole_msg_len; i++) { exactBytes[i] = bufferBytes[i + 4]; } handleFinalBytes(exactBytes); exactBytes = null; bufferBytes = null; } if(dataState == OVER) { exactBytes = new byte[whole_msg_len]; for(int i = 0 ; i< whole_msg_len; i++) { exactBytes[i] = bufferBytes[i + 4]; } handleFinalBytes(exactBytes); exactBytes = null; int overLast = bufferBytes.length - whole_msg_len -4; byte[] fromLastBytes = new byte[overLast]; for(int i = 0; i< overLast ; i++) { fromLastBytes[i] = bufferBytes[whole_msg_len+4 +i]; } bufferBytes = fromLastBytes.clone(); handleBytesFromServer(); } } private void handleFinalBytes(byte[] message) { byte[] protocol_bytes = new byte[4]; for(int i = 0 ; i < 4; i++) { protocol_bytes[i] = message[i + 74]; } int protocol = StreamTool.bytesToInt(protocol_bytes); System.out.println("MySocket 收到服务端信息协议号: " + protocol); byte[] protobuf_length_bytes = new byte[4]; for(int i = 0 ; i < 4; i++) { protobuf_length_bytes[i] = message[i + 78]; } int protobuf_length = StreamTool.bytesToInt(protobuf_length_bytes); byte[] protobuf_bytes = new byte[protobuf_length]; for(int i = 0 ; i < protobuf_length; i++) { protobuf_bytes[i] = message[i + 82]; } Message respMsg = GetMessageByProtocol.getMessage(protocol, protobuf_bytes); SocketDataEvent socketDataEvent = new SocketDataEvent(this, protocol, respMsg); MySocket.notifyListener(socketDataEvent); } private int getDataState(short whole_msg_len, int count) { int dataState = -1; if(whole_msg_len + 4 == count) dataState = EQUAL; if(whole_msg_len + 4 > count) dataState = LACK; if(whole_msg_len + 4 < count) dataState = OVER; return dataState; } }

上一篇:技术线?还是技术管理线?
下一篇:Android 仿联系人列表 实现ListView的A-Z字母排序和过滤搜索功能,并挤压效果(一)

相关文章

相关评论