这个问题曾经困扰姐很久,但因为只是延时,而数据仍然正确,就将这个问题放在一边了。
昨天开始研究,以为是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;
}
}