如何在写入tcp套接字时适应时序变化?

时间:2016-04-07 00:46:18

标签: c++ sockets tcp winsock2

作为测试,我将一系列字节数组写入Android应用程序的tcp套接字,并在C ++应用程序中读取它们。

爪哇

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会以这种方式定期使用,但我不清楚如何缓解这个问题。

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

2 个答案:

答案 0 :(得分:2)

var payload =
      {
        "countryCode": "94",
        "mobileNumber": "0766075555",
        "getGeneratedOTP": true
      };

  var header=
      {
        "application-Key":"application_key_value"
      };


  var options =
   {
     "method" : "POST",
     "headers":header,
     "muteHttpExceptions": true,
     "contentType":"application/json",
     "payload" :  payload
   };

  var request=UrlFetchApp.getRequest("https://sendotp.msg91.com/api/generateOTP", options)
  Logger.log(request)
  var response=UrlFetchApp.fetch("https://sendotp.msg91.com/api/generateOTP", options);
  Logger.log(response);

问题出在这里。它应该是:

for (int i = 0; i < 3; i++)

您正在打印出可能未收到的数据。这是对“垃圾价值”的解释。

您不能假设for (int i = 0; i < iResult; i++) 填充缓冲区。

在此循环之前,您还必须检查recv()的-1和0,并采取相应的操作,每种情况都不同。

答案 1 :(得分:1)

正如您所指出的,TCP是基于流的,因此没有内置的方式来说明这些特定的数据块&#34;。你想要做的是添加自己的&#34;消息框架&#34;。一种简单的方法称为&#34;长度前缀&#34;。您首先发送数据包的大小,然后是数据包本身。然后接收者将知道他们什么时候获得了所有数据。

发送方

  1. 发送数据包的长度(作为已知大小 - 比如32位int)
  2. 发送数据包数据
  3. 接收方

    1. 读取数据包的长度
    2. 读取多个字节的数据
    3. 处理完全接收的数据包
    4. 查看此文章以获取更多信息:http://blog.stephencleary.com/2009/04/message-framing.html