我有一个客户端/服务器应用程序,它使用BufferedOutputStream / BufferedInputStream
. 通信协议如下:
发送部分:
- 第一个字节是要执行的动作
- 接下来的 4 个字节是消息的长度
- 接下来的 x 个字节(x=消息长度)是消息本身
接收部分:
- 读取第一个字节以获取操作
- 读取接下来的 4 个字节以获取消息长度
- 读取 x(在上一步中获得)字节以获取消息
现在的问题是,有时当我在服务器部分发送消息的长度(例如:23045)时,当我收到它时,我会得到一个巨大的整数(例如:123106847)。
一个重要的线索是,只有当消息超过多个字符(在我的情况下 > 10K)时才会发生这种情况,如果我发送了一条较小的消息(例如 4-5k),一切都会按预期工作。
客户端发送部分(outputStream/inputStream 为 BufferedXXXStream 类型):
private String getResponseFromServer( NormalizerActionEnum action, String message) throws IOException{
writeByte( action.id());
writeString( message);
flush(;
return read();
}
private String read() throws IOException{
byte[] msgLen = new byte[4];
inputStream.read(msgLen);
int len = ByteBuffer.wrap(msgLen).getInt();
byte[] bytes = new byte[len];
inputStream.read(bytes);
return new String(bytes);
}
private void writeByte( byte msg) throws IOException{
outputStream.write(msg);
}
private void writeString( String msg) throws IOException{
byte[] msgLen = ByteBuffer.allocate(4).putInt(msg.length()).array();
outputStream.write(msgLen);
outputStream.write(msg.getBytes());
}
private void flush() throws IOException{
outputStream.flush();
}
服务器部分(_input/_output 是 BufferedXXXStream 类型)
private byte readByte() throws IOException, InterruptedException {
int b = _input.read();
while(b==-1){
Thread.sleep(1);
b = _input.read();
}
return (byte) b;
}
private String readString() throws IOException, InterruptedException {
byte[] msgLen = new byte[4];
int s = _input.read(msgLen);
while(s==-1){
Thread.sleep(1);
s = _input.read(msgLen);
}
int len = ByteBuffer.wrap(msgLen).getInt();
byte[] bytes = new byte[len];
s = _input.read(bytes);
while(s==-1){
Thread.sleep(1);
s = _input.read(bytes);
}
return new String(bytes);
}
private void writeString(String message) throws IOException {
byte[] msgLen = ByteBuffer.allocate(4).putInt(message.length()).array();
_output.write(msgLen);
_output.write(message.getBytes());
_output.flush();
}
....
byte cmd = readByte();
String message = readString();
任何帮助将不胜感激。如果您需要更多详细信息,请告诉我。
更新:由于Jon Skeet和EJP的评论,我意识到服务器上的读取部分有一些毫无意义的操作,但抛开这一点,我终于明白了问题所在:关键是我保持流全长打开应用程序和前几次我发送的消息长度我能够在服务器端读取它但是正如Jon Skeet指出的那样,数据不会一次全部到达所以当我尝试再次读取消息长度时我我实际上是从消息本身中读取信息,这就是为什么我有虚假消息长度的原因。
〜而不是发送数据长度然后一次读取它,我发送它没有长度,我一次读取一个字节,直到完美工作的字符串结尾
private String readString() throws IOException, InterruptedException {
StringBuilder sb = new StringBuilder();
byte[] bytes = new byte[100];
int s = 0;
int index=0;
while(true){
s = _input.read();
if(s == 10){
break;
}
bytes[index++] = (byte) (s);
if(index == bytes.length){
sb.append(new String(bytes));
bytes = new byte[100];
index=0;
}
}
if(index > 0){
sb.append(new String(Arrays.copyOfRange(bytes, 0, index)));
}
return sb.toString();
}