使用Java Client读取TCP时丢失/丢弃数据包

时间:2011-06-28 22:21:06

标签: java tcp packets

我正在将C ++客户端更改为Java版本 - 这只是我正在尝试的一项练习。

原始C ++代码非常有效。 Servce端发送一个DWORD然后客户端查找它然后读取253个字节的数据。我已经在Java中尝试了这个并取得了很大的成功,客户端正在丢弃大量的数据包~20个中有1个通过。下面是我尝试过的几个不同的代码块。如果有人能在我出错的时候告诉我,我非常感激。

由于

标记

尝试1:

        //Create socket connection
    try
    {
        client = new Socket("localhost", 7651);
        //in = client.getInputStream();
        reader = new BufferedReader(new
                InputStreamReader(client.getInputStream(), "ISO-8859-1"));
    } 
    catch (UnknownHostException e) 
    {
        System.out.println("Unknown host: localhost");
        System.exit(1);
    } 
    catch  (IOException e) 
    {
        System.out.println("No I/O");
        System.exit(1);
    }

    //Receive data from ROS SerialtoNetwork server

    while (true)
    {
        // Read repeatedly until the expected number of chars has been read:
        char[] buf = new char[300];
        int numberRead = 0;

        int numberToRead = 257;
        for (int totalCharsRead = 0; totalCharsRead < numberToRead; ) 
        {
            int numberLeft = numberToRead - totalCharsRead;

            try {
                numberRead = reader.read(buf, totalCharsRead, numberLeft);

                if (numberRead < 0) 
                {
                    // premature end of data
                    break;
                } 
                else 
                {
                    totalCharsRead += numberRead;
                }               
            } 
            catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        String lstr = new String(buf);
        System.out.print(lstr);

        System.out.println("");
        System.out.println("Bytes Received:" + numberRead);
    }

尝试2:

        //Create socket connection
    try
    {
        client = new Socket("localhost", 7651);
        in = client.getInputStream();           
    } 
    catch (UnknownHostException e) 
    {
        System.out.println("Unknown host: localhost");
        System.exit(1);
    } 
    catch  (IOException e) 
    {
        System.out.println("No I/O");
        System.exit(1);
    }

    //Receive data from ROS SerialtoNetwork server

    try
    {
        while (true)
        {
            byte[] cbuf = new byte[300];
            int lBytesAvail = in.available();//read(cbuf, 0, 4);

            if (lBytesAvail > 253)
            {
                in.read(cbuf, 0, 4);
                int lBytesRead = in.read(cbuf, 0, 253);

                String lstr = new String(cbuf);
                System.out.print(lstr);

                System.out.println("");
                System.out.println("Bytes Received:" + lBytesRead);
            }

        }
    } 
    catch (IOException e)
    {
        System.out.println("Read failed");
        System.exit(1);
    }

3 个答案:

答案 0 :(得分:2)

在“尝试1”中,您正在打印numberRead,而不是totalCharsReadnumberRead是上次操作中读取的数字字符,而不是缓冲区中的总数。您可以通过尽可能地限制局部变量的范围来避免此错误,而不是过早地使用虚拟值初始化它们。这使得您的代码也更具可读性。

使用TCP,数据包不会在Java级别静默“丢弃”。这是在OS级别或更低级别发生的事情。 Java运行时中的任何问题都会引发异常。

答案 1 :(得分:0)

如果发件人正在发送二进制数据,那么您首先会使用Reader咆哮错误的树。使用DataInputStream.readInt()读取DWORD,然后使用DataInputStream.readFully()读取数据。抛弃所有可怕的循环/计数代码。

答案 2 :(得分:0)

我尝试过你的代码 - 大大减少了fp!结果仍然相同。我已尝试使用readInt()并且只读取257个字节(总计包含DWORD)查看数据,它几乎总是丢失30/31数据包 - 这是可疑的!代码如下:

         try
     {
         lSocket = new Socket("localhost", 7651);
         lDataStream = new DataInputStream(lSocket.getInputStream());

     }
     catch (UnknownHostException e)
     {
         System.out.println("Unknown host: localhost");
         System.exit(1);
     }
     catch  (IOException e)
     {
         System.out.println("No I/O");
         System.exit(1);
     }

     //Receive data from ROS SerialtoNetwork server

     try 
     {
         while(true)
         {
            //in.readInt();
            byte[] cbuf = new byte[257];
            lDataStream.readFully(cbuf);        

            String lstr = new String(cbuf);
            System.out.print(lstr);

            System.out.println("");
         }            
    } 
    catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

示例数据(它是二进制文件,第三列是数据包seq id - 无法显示所有内容,因为有些是非打印字符,因此这里显示的只是数据的一部分。但我看到了整个当它读取数据包时会通过)

25,253,31,26,129,105,94,65,67,31,23,2,9,791,56,12,88,64,2,

32-61缺失/未读

25,253,62,26,129,105,94,65,67,31,23,2,9,5,57,11,88,64,2,

63-91缺少/未读

25,253,92,26,129,105,94,65,67,31,23,2,9,5,57,12,88,64,2,