【问题标题】:Delimit data coming from socket分隔来自套接字的数据
【发布时间】:2012-06-20 20:47:01
【问题描述】:

在我的 Java 应用程序中,打开了一个 Socket,并且正在从其 InputStream 中读取数据。

在最佳条件下,每个传入的数据包都会导致调用 read() 返回其应用层数据。这就是我想要得到的 - 每个 数据包 一个“消息”。

但是,数据可能会根据 getReceiveBufferSize() 返回的内容缓存在套接字中。如果发生这种情况并从中读取流,则可能存在来自多个数据包的数据。

是否有其他方法可以从单个数据包中获取数据,或者这是否违反了抽象层? 或者,是否可以为数据附加到缓冲区设置某种分隔符?还是平台级别的事情是做不到的?

这里有一些示例代码来演示我在做什么:

import java.io.InputStream;
import java.net.Socket;

public class Belnets {


public Belnets() {
    try{
        Socket s = new Socket("address", 23);
        System.out.println("platform will buffer this much: "+s.getReceiveBufferSize());
        InputStream sin = s.getInputStream();
        byte[] data = new byte[1024];
        int c;
        while(true){
            c = sin.read(data);
            for(int i=0; i<c; i++){
                System.out.print((char)data[i]);
            }
            System.out.println("=END OF READ=");

            //if you dont do this, read() seems to return once for each packet as this loop 
            //appears to be running fast enough to keep up with the rate of data that comes in.
            //otherwise data gets buffered and you get multiple packets worth of data before seeing
            //=END OF READ=
            Thread.sleep(1000);     

        }

    }catch(Exception e){
        e.printStackTrace();
    }
}   



public static void main(String args[]){
    new Belnets();
}

}

【问题讨论】:

  • while(true) 应该是while(c != -1)
  • 你能改变数据的发送方式吗?如果是,您可以在发送的消息的末尾添加一个消息结束分隔符,您可以在接收数据时查找(确保您选择的分隔符不能正常作为消息的一部分)

标签: java sockets networking


【解决方案1】:

Java API 不提供任何读取 TCP 数据包的方法。它是基于流的,您绝对无法一次读取一个数据包。

如果要发送和接收多条消息,则需要实现应用程序级协议,例如,该协议可能在消息之间使用特定的分隔符,或者发送消息的长度后跟消息体本身。

【讨论】:

    【解决方案2】:

    在最佳条件下,传入的每个数据包都会导致调用 read() 返回其应用层数据。

    没有。这不是“最佳条件”,这纯粹是运气。 Java 或底层 BSD 套接字 API 或 TCP RFC 中没有任何内容赋予任何依赖该行为的权利。 TCP是流协议,句号,API是字节流API,也是句号。

    如果您想要应用程序消息或数据包,您必须自己实现它们,通过:

    1. 为每条消息添加一个长度字的前缀。
    2. 使用更高级别的协议,例如对象序列化、XDR 等。
    3. 使用自描述协议,例如 XML、JSON 等。

    在每种情况下,您都必须在接收器处循环读取,直到获得完整的消息。

    【讨论】:

      【解决方案3】:

      您的 while 循环需要更改:

      while (true) {
          c = sin.read(data);
          if (c < 0)
              break;    // quit if there's nothing else to read.
          for(int i=0; i<c; i++){
              System.out.print((char)data[i]);
          }
      ...
      }
      

      【讨论】:

        【解决方案4】:

        尝试读取 TCP 数据包是不可能的,也不是一个好主意。 TCP 是基于流的,这意味着不能保证所有内容都会同时发送/接收。您可能会考虑使用 UDP(它不太可靠,但所有内容都会立即发送),或者提出您自己的定界方案。 (一种流行的方法是发送“数据包”的长度,然后是实际数据包本身。)

        【讨论】:

          猜你喜欢
          • 2012-06-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-04-25
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多