3

我正在尝试使用 Java 将套接字发送到服务器:

_socket   = new Socket(host, port);
_writer   = new DataOutputStream(_socket.getOutputStream());

public void send(String data){
    _writer.writeBytes( data );
    _writer.flush();
}

我想将数据作为同一个数据包发送,有时它会分成多个数据包。我不知道它是否足够清楚,我缺少一些词汇。

如果我发送:

“0123456789abcdefghijklmnopqrstuvwxyz”

服务器可能会将数据接收到 3 个数据包中:

  1. "0123456"
  2. "789abcdefghijklmno"
  3. "pqrstuvwxyz"

有没有办法不将您发送的数据分成多个数据包?


BufferedOutputStream似乎解决了这个问题。

4

5 回答 5

2

BufferedOutputStream似乎解决了这个问题。

于 2013-05-12T17:52:53.880 回答
0

也许设置缓冲区大小会有所帮助:

http://docs.oracle.com/javase/6/docs/api/java/net/Socket.html#setSendBufferSize%28int%29

不过,我还没有尝试过这个选项。我必须承认,我希望缓冲区不仅仅是像你的情况那样的十几个字节。

于 2013-05-12T13:51:42.177 回答
0

我做了一些测试,它在我的情况下很完美。我在另一边仅一次读取就收到了全部数据。

我使用这个功能:

public void send(String data)
{
   try
   {
       socket.getOutputStream().write(data.getBytes());
   }
   catch (Exception e)
   {
   }
}

我认为即使您使用 3 次读取来获取数据,也不一定意味着您收到了 3 个数据包,可能是 1、2 甚至超过 3 个。如果不知道服务器如何读取数据,很难正确回答这个问题。例如,如果队列中有 200 个字节并且我读取了 50 个字节的缓冲区,那么我需要 4 次读取来获取数据。这很明显,但值得一提。

于 2013-05-12T14:34:08.007 回答
0

我必须承认我不知道Sockets分割的数据,但我想这是可以预料的。您拥有的一种选择是简单地使用一个字符或字符组合来表示传输的结束。IE:

String data = "Hello there, this is a long packet";
String delimiter = "ENDOFPACKET"; // Obviously, it will need to be more complex.

String packet = data + delimiter;
send(packet);

在您的阅读器中,无需处理每个数据包,而是简单地连接到一个字符串,直到delimiter找到该值。

于 2013-05-12T13:39:09.877 回答
0

这是流协议的基本特征,例如 TCP/IP 或本地套接字:它是保证以正确顺序传送的字节流,就是这样,没有数据包边界。

所以你需要你自己的协议来分离数据包。有两种基本方法。

首先,您可以有一个特殊的字节或字节序列,例如文本流中的简单换行符或字节 0,它标志着消息的结束。

其次,你可以有一个数据包头,它可以像 32 位原始二进制数一样简单,通常按照网络字节顺序,告诉消息的大小,然后是实际消息数据的字节数。这适用于二进制数据。

或者使用混合方法:首先读取一行文本标题,在下一个换行符处结束,您将其解析为文本数据,其中包括长度。然后读取那么多字节的原始二进制数据,然后读取下一个标题行作为文本,依此类推。当您可以直观地看到您的服务器和客户端是否保持同步时,这更容易调试,并且也很容易扩展,因为标头不是固定大小的。

于 2013-05-12T18:13:19.217 回答