3

在我的 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();
}

}
4

4 回答 4

5

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

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

于 2012-06-20T21:02:04.610 回答
2

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

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

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

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

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

于 2012-06-21T03:43:50.943 回答
0

您的 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]);
    }
...
}
于 2012-06-20T21:04:15.917 回答
0

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

于 2012-06-20T21:11:31.547 回答