【发布时间】:2016-04-07 00:46:17
【问题描述】:
作为测试,我正在将一系列字节数组从 Android 应用程序写入 tcp 套接字,并在 C++ 应用程序中读取它们。
Java
InetAddress address = InetAddress.getByName("192.168.0.2");
Socket socket = new Socket(address, 1300);
DataOutputStream out = new DataOutputStream(socket.getOutputStream())
...
if(count == 0) {
out.write(first, 0, first.length);
} else if(count == 1) {
out.write(second, 0, second.length);
}
C++
do {
iResult = recv(ClientSocket, recvbuf, 3, 0);
for (int i = 0; i < 3; i++) {
std::cout << (int)(signed char)recvbuf[i] << std::endl;
}
} while (iResult > 0);
就目前而言,在第一个收据上,recv[2] = -52,我认为这是一个垃圾值,因为在我收到第一个字节数组时,输出流还没有写入第二个字节数组段。
但是,当我在 ListenSocket 接受连接后暂停时:
ClientSocket = accept(ListenSocket, NULL, NULL);
std::cin.ignore();
...让发送方有时间对流进行两次写入,recv[2] = 3,这是第二个写入字节数组的第一个值。
如果我最终想要发送和接收离散数组的恒定流,我如何确定在收到一个数组的最后一个值后,缓冲区中的下一个值是下一个数组的第一个值还是是不是垃圾值?
我考虑过udp比较适合发送一系列离散的数据集,但是我需要tcp的可靠性。我想 tcp 经常以这种方式使用,但我不清楚如何缓解这个问题。
编辑: 在我编写此测试的实际应用程序中,我确实实现了长度前缀。我认为这无关紧要。即使我知道我在数据集的末尾,我也需要知道缓冲区中的下一个值是垃圾还是下一组的开头。
【问题讨论】:
-
你不能让 TCP 做到这一点。 TCP 将所有数据视为单个字节流。你应该发送数组有多大,在接收器上读取数组有多大,然后读取那么多的东西。
-
半离题:在
iResult = recv(ClientSocket, recvbuf, 3, 0);iResult是读取的字节数,如果有的话,或者错误时为负值。因此,在检查并处理了否定情况之后,打印结果的for循环应该类似于:for (int i = 0; i < iResult; i++)来处理您读取数据但没有获得三个字节的情况。 -
@immibis 你的意思是说TCP不能也不用这种方式?我必须使用 udp 吗?
-
@Jayz7522 不,我是说如果您以块的形式发送数据,您将不会以块的形式接收它。如果你想要积木,你必须发明自己的积木。
-
recv 的最后一个 flags 参数可以传递给
MSG_WAITALL,在这种情况下它将阻塞并确保在recv返回之前读取3 个字节,否则将报告错误/断开连接。这可以简化您的代码,只要您可以相信 Java 端在发送 3 个字节之前没有崩溃。更一般地说,您可能不想在服务器和客户端中硬编码3,因此最初可能会发送一个固定长度的二进制编码消息长度。