java BufferedReader特定长度返回NUL字符

时间:2010-04-22 01:47:14

标签: java sockets

我有一个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,并将它们附加到我的“截断”消息,确认长度正常。

它也有效,但我真的认为我可以做得更好,比如在阅读之前检查缓冲区中我需要的字符总数是否可用,但找不到正确的方法...

任何想法/指针?

谢谢!

2 个答案:

答案 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>");
      }
   }