Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何适应写入tcp套接字时的时间变化? 作为一个测试,我正在编写一系列字节数组到一个Android应用程序的TCP套接字,并在C++应用程序中读取它们。p>_C++_Sockets_Tcp_Winsock2 - Fatal编程技术网

如何适应写入tcp套接字时的时间变化? 作为一个测试,我正在编写一系列字节数组到一个Android应用程序的TCP套接字,并在C++应用程序中读取它们。p>

如何适应写入tcp套接字时的时间变化? 作为一个测试,我正在编写一系列字节数组到一个Android应用程序的TCP套接字,并在C++应用程序中读取它们。p>,c++,sockets,tcp,winsock2,C++,Sockets,Tcp,Winsock2,Java InetAddress address = InetAddress.getByName("192.168.0.2"); Socket socket = new Socket(address, 1300); DataOutputStream out = new DataOutputStream(socket.getOutputStream()) C++ do { iResult = re

Java

InetAddress address = InetAddress.getByName("192.168.0.2");                          
Socket socket = new Socket(address, 1300);                   
DataOutputStream out = new DataOutputStream(socket.getOutputStream())

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]=3,这是第二个写入字节数组的第一个值

如果我最终想要发送和接收离散数组的恒定流,那么在接收到一个数组的最后一个值后,如何确定缓冲区中的下一个值是下一个数组的第一个值还是垃圾值

我认为udp更适合发送一系列离散数据集,但我需要tcp的可靠性。我认为tcp经常以这种方式使用,但我不清楚如何缓解这个问题

编辑:
在我编写此测试的实际应用程序中,我实现了长度前缀。但我认为这并不重要;即使我知道自己在一个数据集的末尾,我也需要知道缓冲区上的下一个值是垃圾值还是下一个数据集的开头。

正如您所指出的,TCP是基于流的,因此没有内置的方式来表示“这是一个特定的数据块”。您要做的是添加您自己的“消息框架”。一种简单的方法叫做“长度前缀”。首先发送数据包的大小,然后发送数据包本身。然后接收器就会知道他们什么时候得到了所有的数据

发送端

  • 发送数据包的长度(以已知大小表示——比如32位整数)
  • 发送分组数据
  • 接收端

  • 读取数据包的长度
  • 读取那么多字节的数据
  • 处理完全接收的数据包
  • 查看本文了解更多信息:

    for(inti=0;i<3;i++)
    
    问题就在这里。应该是:

    for (int i = 0; i < iResult; i++)
    
    for(int i=0;i
    您正在打印可能未收到的数据。这就是“垃圾价值”的解释

    您不能假设
    recv()
    填充了缓冲区


    在此循环之前,您还必须检查
    iResult
    中的-1和零,并采取相应的措施,这在每种情况下都是不同的。

    您不能让TCP这样做。TCP将所有数据视为单个字节流。你应该发送数组有多大,然后在接收器上读取数组有多大,然后读取那么多内容
    iResult
    是读取的字节数(如果有),或者是错误时的负值。因此,在检查并处理否定大小写后,用于打印结果的
    循环应该类似于:
    for(int i=0;i
    来处理读取数据但没有得到三个字节的情况。@immibis您的意思是说TCP不能也没有以这种方式使用吗?我必须使用udp?@Jayz7522不,我是说如果你以块的形式发送数据,你就不会以块的形式接收数据。如果需要块,您必须创建自己的块。可以传递最终标志参数
    MSG_WAITALL
    ,在这种情况下,它将阻止并确保在
    recv
    返回之前读取所需的3个字节,或者它将报告错误/断开连接。这可以简化代码,只要您相信Java端在发送3个字节之前不会崩溃。一般来说,您可能不希望在服务器和客户端中硬编码
    3
    ,因此最初可以发送固定长度的二进制编码消息长度。谢谢。我已经在我的实际应用程序中实现了一个长度前缀(不过,我会查看这篇文章,看看它是否需要改进);然而,我认为这并不能解决这个问题。仅仅因为我知道我在一个块的末尾,并不意味着我知道下一个字节是下一个块的开头还是垃圾。对吗?@Jayz7522你不会收到任何垃圾。@Jayz7522我认为你看到的“垃圾”是你打印出未初始化的内存。@Jayz7522:关键的是,根据这个答案中提倡的长度前缀,在每个阶段,你都知道你希望读取多少数据:前四个字节,然后,显示四字节数的字节数。对于每一个问题,你要么循环调用
    recv
    ,直到你组装了那个数量的字节,要么使用
    MSG_WAITALL
    ,正如我在你的问题下的评论中所解释的那样。看起来我并没有像我想的那样离题。是的,我对recv()返回的内容做了错误的假设。非常感谢。
    ClientSocket = accept(ListenSocket, NULL, NULL);
    std::cin.ignore();
    
    for (int i = 0; i < 3; i++)
    
    for (int i = 0; i < iResult; i++)