我有一个TCP套接字客户端从服务器接收消息(数据)。 消息的类型长度(2字节)+数据(长度字节),由STX& ETX字符。
我正在使用bufferedReader来检索两个第一个字节,解码长度,然后从相同的bufferedReader再次读取适当的长度并将结果放入char数组中。
大多数时候,我没有问题,但有些(收到的数千条消息中有1条),当试图从阅读器读取(长度)字节时,我只得到它的一部分,我的数组的其余部分是充满了“NUL”字符。我想这是因为缓冲区尚未填充。
char[] bufLen = new char[2];
_bufferedReader.read(bufLen);
int len = decodeLength(bufLen);
char[] _rawMsg = new char[len];
_bufferedReader.read(_rawMsg);
return _rawMsg;
我用几种迭代的方式解决了这个问题:
首先我测试了我的数组的最后一个字符:如果它不是ETX,我会逐个读取bufferedReader中的字符,直到我到达ETX,然后重新启动我的常规例程。该 结果是我基本上会丢弃一条消息。
然后,为了仍然检索该消息,我会在我的“截断”消息中找到NUL字符的第一个出现,阅读&一次存储一个额外的字符,直到我到达ETX,并将它们附加到我的“截断”消息,确认长度正常。
它也有效,但我真的认为我可以做得更好,比如在阅读之前检查缓冲区中我需要的字符总数是否可用,但找不到正确的方法...
任何想法/指针?
谢谢!
答案 0 :(得分:2)
InputStream读取方法可能返回短读取;您必须检查返回值以确定读取的字符数,并继续读取循环,直到获得所需的数字。该方法可能会阻止,但只会阻塞某些数据,而不一定是您请求的所有数据。
大多数人最终都会编写一个“readFully”方法,比如DataInputStream,它会读取预期的数据量,或者抛出IOException:
static public int readFully(InputStream inp, byte[] arr, int ofs, int len) throws IOException {
int rmn,cnt;
for(rmn=len; rmn>0; ofs+=cnt, rmn-=cnt) {
if((cnt=inp.read(arr,ofs,rmn))==-1) {
throw new IOException("End of stream encountered before reading at least "+len+" bytes from input stream");
}
}
return len;
}
答案 1 :(得分:1)
这是我用于测试的示例服务器 主rcv的结构类似于
while((chars_read = from_server.read(buffer)) != -1)
{
to_user.write(buffer,0,chars_read);
to_user.flush();
}
实际的整个服务器低于......
public static void main(String[] args) throws IOException
{
try
{
if (args.length != 2)
throw new IllegalArgumentException("Wrong number of Args");
String host = args[0];
int port = Integer.parseInt(args[1]);
Socket s = new Socket(host,port);
final Reader from_server = new InputStreamReader(s.getInputStream());
PrintWriter to_server = new PrintWriter(new OutputStreamWriter(s.getOutputStream()));
BufferedReader from_user = new BufferedReader(new InputStreamReader(System.in));
final PrintWriter to_user = new PrintWriter(new OutputStreamWriter(System.out));
to_user.println("Connected to " + s.getInetAddress() + ":" + s.getPort());
Thread t = new Thread()
{
public void run()
{
char [] buffer = new char[1024];
int chars_read;
try
{
while((chars_read = from_server.read(buffer)) != -1)
{
to_user.write(buffer,0,chars_read);
to_user.flush();
}
}
catch(IOException e)
{
to_user.println(e);
}
to_user.println("Connection closed by server");
to_user.flush();
System.exit(0);
}
};
t.setPriority(Thread.currentThread().getPriority() + 1);
t.start();
String line;
while ((line = from_user.readLine()) != null)
{
to_server.println(line);
to_server.flush();
}
//t.stop();
s.close();
to_user.println("Connection closed by client");
to_user.flush();
}
catch(Throwable e)
{
e.printStackTrace();
System.err.println("Usage : java TCPClient <hostname> <port>");
}
}