TCP插座接收并处理多个消息(TCP Socket receiving and processing

2019-11-01 09:25发布

我有在获得从TCP套接字来的所有数据一些麻烦。

在我的服务器,我是从这样一个socket读取数据:

        int len;
        byte[] buffer = new byte[2000];
        try {
            this.in = new DataInputStream(this.socket.getInputStream());
            this.out = new DataOutputStream(this.socket.getOutputStream());
            running = true;

            while (running) {
                len = in.read(buffer);
                if (len < 0) {
                    running = false;
                } else {
                    parsePacket(buffer, len);
                }
            }

        } catch (IOException ex) {
            System.out.println("Catch IOException: " + ex);
            ex.printStackTrace();
        } finally {
            try {
                System.out.println("Closing");
                in.close();
                out.close();
                socket.close();
            } catch (IOException ex) {
                System.out.println("Finally IOException: " + ex);
            }
        }

数据包的格式是这样的:

[HEADER] [DATA] [TERMINATOR]

  • 头 - >字符序列标识消息(有关数据包的长度没有信息)的开始;
  • 数据- >共分细分,如:[尺寸段用。 1] [数据波段。 1] [大小波段。 2] [数据波段。 2] [尺寸波段。 3] [数据波段。 3] ... [大小波段。 N] [数据波段。 N]
  • 终止子 - > [0×00]

数据被接收到的非常快(有时为200ms或更小),所以有时read(buffer)填充buffer中包含的消息:

  • [头1] [DATA1] [TERM1]或,
  • [头1] [DATA1] [TERM1] [HEADER2] [DATA2] [TERM2] ............. [HEADER N] [数据N] [TERM N],或
  • [头1] [DATA1] [TERM1] [HEADER2] [DATA2] [TERM2] ............. [HEADER N] [DAT(最后一个消息不完全的)

所述parsePacket()方法能够解析的消息上面的格式和它是否有下一个多个消息,它们也将被(递归地)进行解析。 但是,如果它是不完整也不会解析最后一条消息(我不希望这样,但我没有找到一个合适的解决方案到现在为止)。

消息内部发出的数据被存储在一个MySQL数据库(使用JDBC驱动程序)。 消息的每个解析可能涉及多个数据库查询。 由于我只使用一个线程接收,分析和存储数据,代码的执行是没有那么快,因为它应该...的数据应该被接收并快速存储成为可能。

我想讨论的一些要点:

  • 有什么能得到不失去他们中的一些所有消息的最佳方法?
  • 我怎么能提高数据被接收和存储的方式吗? (该数据应该存储尽可能快的!)

Answer 1:

由于TCP是已经流协议以读取该数据的最简单的方法是作为一个流。 我想补充一个监听器来处理事件。

DataInputStream dis = new DataInputStream(new BufferedInputStream(socket.getInputStream()));

try {
   while(true) {
       listener.startOfMessage();
       for(int segSize; (segSize = dis.readInt()) > 0;) {
          byte[] bytes = new byte[segSize];
          dis.readFully(bytes);
          listener.data(bytes);
       }
       int footer = dis.read();
       // check footer ??
       listener.endOfMessage();
   }
} catch(EOFException endOfStream) {
   // handle or ignore
} finally {
   // close everything.
}

当你做缓冲自己,你也必须重新组装的消息,并保留不完整的信息,这是配发头痛的没有任何好处在这里。

数据被接收到的非常快(有时为200ms或更小)

200 ms是你拥有的每CPU约6亿个时钟周期。 这是一个永恒的计算机。 :)

上面的代码应在200毫秒20000条消息的顺序处理。 如果你比这需要更多的,你可以使用NIO代替,但我不认为你需要。

该数据应尽可能快存储越好!

我怀疑是MySQL是罚款,这是不是“尽可能快地”,但我没有看到你说的不使用它的任何理由。



Answer 2:

你是生产Stringbuffer ,对不对? 在这种情况下,我建议你修改的界面parsePacket方法,改造循环,这样的事情:

        String tail = "";
        String line = "";
        while (running) {
            len = in.read(buffer);
            if (len < 0) {
                running = false;
            } else {
                line = tail + new String(buffer);
                tail = parsePacket(line, len);
            }
        }

parsePacket你要剪线的无端接尾及方法返回。



Answer 3:

TCP提供传输服务,不包服务。 为了实现“打包”协议有帧数据包本身。 在你的情况下,取景与实现[TERMINTAOR]标记。 在客户端,你应该做的是:

  1. 检查您的buffer包含标记。 如果它不然后发出read到的数据添加到您的buffer ,并返回步骤1。
  2. 解析并从缓冲器消耗的分组
  3. 返回到步骤1。


Answer 4:

TCP是流协议。 它提供的所有书面插槽上一端插座在它们的排列顺序,另一端的字节数。 它并不能保证他们会在尽可能它们放在同一大小的“块”到达。读操作可能会比写在任何给定的写或多或少字节。 但是,所有的字节在那里,他们都按正确的顺序。

对此的解决方案是使用限定消息边界的协议 - 无论是一个消息终止子,或长度头部,或自描述格式如XML。



Answer 5:

TCP是流协议,它不从一个端口保证消息的大小,以另一个具有相同块大小的。 在阅读你可能会得到更多或更少的被写在一个写字节量。



文章来源: TCP Socket receiving and processing multiple messages