在我的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();
}
}
答案 0 :(得分:5)
Java API不提供任何读取TCP数据包的方法。它是基于流的,你绝对无法一次读取一个数据包。
如果要发送和接收多条消息,则需要实现应用程序级协议,该协议可能使用消息之间的特定分隔符,或者发送消息的长度,后跟消息正文本身,例如。 / p>
答案 1 :(得分:2)
在最佳条件下,每个进入的数据包都会导致调用read()返回其应用程序层数据。
没有。这不是'最佳条件',这纯粹是运气。 Java或底层BSD套接字API或TCP RFC中没有任何内容可以依赖该行为。 TCP是一种流协议,周期,API是字节流API,也是句号。
如果您需要自己的应用程序消息或数据包,请通过以下方式实现:
在每种情况下,您必须在接收器中循环读取,直到您收到整条消息。
答案 2 :(得分: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]);
}
...
}
答案 3 :(得分:0)
尝试读取TCP数据包并不是真的可能或者是个好主意。 TCP是基于流的,这意味着不能保证一次性发送/接收所有内容。您可能会考虑使用UDP(不太可靠,但一切都会立即发送),或者提出自己的分界方案。 (一种流行的方法是发送“数据包”的长度,然后发送实际的数据包本身。)