【问题标题】:Sending Large Base64 String over TCP Socket通过 TCP 套接字发送大型 Base64 字符串
【发布时间】:2020-02-17 16:15:35
【问题描述】:

我正在尝试使用 C++ 中的 GO 和 TCP 服务器从 TCP 客户端发送 Base64 编码图像。

这里是 C++ Receiver 的代码 sn-p

std::string recieve(int bufferSize=1024,const char *eom_flag = "<EOF>"){
char buffer[bufferSize];
std::string output;
int iResult;
char *eom;
do{
    iResult = recv(client, buffer, sizeof(buffer), 0);
    //If End OF MESSAGE flag is found.
    eom = strstr(buffer,eom_flag);
    //If socket is waiting , do dot append the json, keep on waiting.
    if(iResult == 0){
        continue;
    }
    output+=buffer;
    //Erase null character, if exist.
    output.erase(std::find(output.begin(), output.end(), '\0'), output.end());
        //is socket connection is broken or end of message is reached.
}while(iResult > -1 and eom == NULL);
//Trim <EOF>
std::size_t eom_pos = output.rfind(eom_flag);
return output.substr(0,eom_pos);}

想法是在找到消息结束之前接收消息,然后继续在同一 TCP 连接上侦听另一条消息。

Golang TCP 客户端代码 sn-p.

//Making connection
connection, _ := net.Dial("tcp", "localhost"+":"+PortNumber)
if _, err := fmt.Fprintf(connection, B64img+"<EOF>"); err != nil {
            log.Println(err)
            panic(err)
        }

尝试过的方法:

  • 增加 C++ 接收器中的缓冲区大小。
  • 从 C++ 接收器中的字符串末尾删除空字符。

观察:

  • 客户端发送的字符串长度是固定的,而接收函数后的字符串长度更大, 随机的。示例:Go 客户端字符串长度为 25243。对于相同的字符串,i 时接收后的长度 在循环中运行发送和接收是 25243、26743、53092、41389、42849。

  • 在将接收到的字符串保存在文件中时,我在字符串中看到 字符。

我正在为 c++ 套接字使用 winsock2.h。

【问题讨论】:

  • recv 不一定会返回缓冲区中可以容纳的字节数 - 该函数返回实际返回的字节数作为其结果。你应该考虑到你目前所做的output+=buffer;。
  • char buffer[bufferSize]; -- 这不是有效的 C++。使用std::vector&lt;char&gt; buffer(bufferSize);
  • 见stackoverflow.com/questions/4840535/c-recv-problem 你可能会遇到同样的问题,因为你将信息写入同一个缓冲区。 (当函数返回时,您永远无法确定将 100% 的消息放入缓冲区,因此您必须将其添加到“完整消息缓冲区”中)
  • 您可能还有另一个问题:由于消息永远不会完全进入缓冲区,因此您可能会在缓冲区中截断“”,因此您永远找不到它(C++ 比网络更快所以你可能会每 2-3 个字符返回一个函数;)
  • 另一个问题:在recv 调用之后,if (iResult == 0) { continue; } 是错误的。 只有次您将获得零返回值是如果/当您的对等方已断开连接。通过使用continue,您只需重复recv,这将再次返回0,从而导致无限循环。

标签: c++ sockets go tcp base64


【解决方案1】:

您将接收到的数据视为 C 字符串 - 以 0 字节结尾的字节序列 - 这是不正确的。

recv 接收一些字节并将它们放入buffer。假设它收到了 200 个字节。

然后你做strstr(buffer,eom_flag);。 strstr 不知道收到了 200 个字节。 strstr 从缓冲区的开头开始,一直查找,直到找到 或 0 字节。它有可能在缓冲区的其他 824 字节中找到 a,即使您没有收到。

然后你做output += buffer;。这也将缓冲区视为以 0 字节结尾。这将查看整个缓冲区(不仅仅是前 200 个字节)以找到一个 0 字节。然后它将到该点的所有内容添加到output。同样,它可能会在缓冲区的最后 824 个字节中找到一个 0 字节,并添加太多数据。它可能在缓冲区中根本找不到 0 字节,然后它将继续从存储在内存中 buffer 旁边的其他变量中添加额外数据。或者它可能会在前 200 个字节中找到一个 0 字节,然后停在那里(但前提是您发送了一个 0 字节)。


您应该注意接收到的字节数(即iResult)并将这些字节数添加到输出中。你可以使用:

output.insert(output.end(), buffer, buffer+iResult);

另外(正如 Phillipe Thomassigny 在评论中指出的那样),“”可能不会一次全部收到。您可能会单独收到“”。您应该检查output 是否有“”,而不是检查buffer 是否有“”。 (这对性能的影响留给读者作为练习)


顺便说一句,这条线目前没有做任何事情:

output.erase(std::find(output.begin(), output.end(), '\0'), output.end());

因为 '\0' 永远不会被添加到 output,因为使用 output += buffer;,'\0' 告诉它在哪里停止添加。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-25
    • 1970-01-01
    • 1970-01-01
    • 2013-06-28
    相关资源
    最近更新 更多