4

我曾经UDP用来发送/接收数据,但我现在想切换到TCP以避免数据包丢失。

我已经阅读了几个教程,TCP并注意到不是使用 DatagramPacket,而是UDP使用TCPInputStream/OutputStream。

我们如何从 DataInputStream 中获取 byte[],类似于以下内容:

byte[] receiveData = new byte[64000];
DatagramPacket receivePacket = new DatagramPacket(receiveData,receiveData.length); 
receiveData=receivePacket.getData();
4

2 回答 2

13

为了通过套接字(流)实现基于消息的协议,您基本上想提出一些消息格式,然后在连接的任一端读/写。一种非常简单的格式是将消息的长度写为 4 字节 int,然后发送消息字节(然后刷新流)。在接收端,读取一个 4 字节的 int,然后准确读取后面那么多字节(注意限制读取方法调用,否则可能会意外读取下一条消息的一部分)。

public void writeMessage(DataOutputStream dout, byte[] msg, int msgLen) {
  dout.writeInt(msgLen);
  dout.write(msg, 0, msgLen);
  dout.flush();
}

public byte[] readMessage(DataInputStream din) {
  int msgLen = din.readInt();
  byte[] msg = new byte[msgLen];
  din.readFully(msg);
  return msg;
}
于 2012-07-21T00:02:08.347 回答
7

答案有 2 个部分。处理与您的问题相关的 2 个独立问题。

1 . 网络事实

TCP本质上是基于流的。即先发送字节[1000],然后发送字节[1200],与发送字节[2200] 一次没有区别。实际通过网络发送的很可能是 2 个数据包,第一个是 1400 字节的数据包,第二个是 800,或 1401 和 799,并且每次都可能不同。接收方无法知道发送方实际上先发送了 1000 个字节,然后发送了 1200 个字节。这是网络设计的。Java 与这个事实无关。你不能用它做任何事情。

2 . Java 实现

在发送方。首先,您需要OutputStream os = tcpsocket.getOutputStream();. 然后,每次,您都需要os.write(byteArray). 在接收方,您需要InputStream is = tcpsocket.getInputStream();. 然后,每次,您都需要is.read(byteArray). 请注意,在接收方,byteArray将返回实际填充的数量。它可以是介于 1 和 的容量之间的任何数字byteArray,并且与发送者实际发送它的方式无关。

为了减轻任务,您可以DataInputStream is = new DataInputStream(tcpsocket.getInputStream());在开始时使用,并在is.readFully(byteArray)每次需要阅读时使用。这样,就可以保证byteArray永远被填满。

But you can never know how many bytes you should receive if the actual length is variable unless you add some extra information. For example, send the length first, using 4 bytes. How you will actually do this is usually closely related to your actual use case. And it's up to you

于 2012-07-21T00:02:57.200 回答