Reputation: 244
This is my socket implementation:
s = new Socket(this.host,this.port);
s.setReceiveBufferSize(2048*2048);
s.setSendBufferSize(2048*2048);
And when I receive too much data my data is cropped like this:
Recieving Message: {"cmd":"209","args":{"type":1,"messages":[{...},{...},{...},{..{...},{�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������...
[EDIT] I create a class called InputReader that implements a Runnable, this class inside has a run method and a while condition:
private class InputReader implements Runnable {
private DarkStarSocketClient main;
private InputStream in;
private boolean disconnected = false;
public InputReader(DarkStarSocketClient main, InputStream in) {
this.main = main;
this.in = in;
}
public void run() {
while (!disconnected) {
try {
byte hi = (byte) in.read();
if (hi == -1) {
main.disconnect();
MessageBuffer dummy = new MessageBuffer(new byte[0]);
postRequest(dummy);
break;
}
byte lo = (byte) in.read();
int len = ((hi & 255) << 8) + (lo & 255) << 0;
byte[] msgBytes = new byte[len];
in.read(msgBytes);
MessageBuffer buf = new MessageBuffer(msgBytes);
handleApplicationMessage(buf);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
This is the implementation of the function handleApplicationMessage:
private void handleApplicationMessage(MessageBuffer msg) throws Exception {
byte command = msg.getByte();
switch (command) {
case SimpleSgsProtocol.LOGIN_SUCCESS:
reconnectKey = msg.getBytes(msg.limit() - msg.position());
loggedIn = true;
responseHandler.loggedIn();
break;
case SimpleSgsProtocol.LOGIN_FAILURE: {
String reason = msg.getString();
responseHandler.loginFailed(reason);
break;
}
case SimpleSgsProtocol.LOGIN_REDIRECT: {
String host = msg.getString();
int port = msg.getInt();
break;
}
case SimpleSgsProtocol.SESSION_MESSAGE: {
checkLoggedIn();
byte[] msgBytes = msg.getBytes(msg.limit() - msg.position());
responseHandler.receivedSessionMessage(msgBytes);
break;
}
case SimpleSgsProtocol.RECONNECT_SUCCESS:
loggedIn = true;
reconnectKey = msg.getBytes(msg.limit() - msg.position());
responseHandler.reconnected();
break;
case SimpleSgsProtocol.RECONNECT_FAILURE:
String reason = msg.getString();
this.disconnect();
break;
case SimpleSgsProtocol.LOGOUT_SUCCESS:
loggedIn = false;
break;
default:
throw new IOException("Unknown session opcode: " + command);
}
}
Upvotes: 2
Views: 193
Reputation: 533442
Most likely you have a bug in your code.
The most common mistake is to ignore the length of data actually read when you call read. e.g.
for(int length; (length = in.read(buffer)) > 0; ) {
// you must use the actual length and not assume the buffer is always full.
If you ignore the length, you assume the whole buffer has useful data when only the start is right.
EDIT: As I guessed you are ignoring the length actually read. The minimum is 1 no matter how big a byte[] you give it.
in.read(msgBytes);
should be
int length = in.read(msgBytes);
// keep reading until you have everything.
Your life would be a lot simpler if you used DataOutputStream and DataInputStream
private final DataInputStream in;
try {
while (!disconnected) {
int length = in.readShort() & 0xFFFF;
byte[] msgBytes = new byte[length];
in.readFully(msgBytes); // keeps reading until the whole buffer is read.
try {
MessageBuffer buf = new MessageBuffer(msgBytes);
handleApplicationMessage(buf);
} catch (Exception ex) {
ex.printStackTrace();
}
}
} catch (EOFException expected) {
} catch (Throwable t) {
System.err.println("Fatal error");
t.printStackTrace();
}
Upvotes: 5