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  整条信息长度(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 listeners = new ArrayList();
	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;
		}
}



你可能感兴趣的:(java,c++,Android,protobuf,google,nio,socket,socketchannel)