通过套接字 c++ 发送长度和数据

Send length and data through socket c++

本文关键字:数据 套接字 c++      更新时间:2023-10-16

所以我目前正在开发一个使用套接字的应用程序,目前一切正常,我只想知道是否有更有效的方法来发送数据和数据的长度而不是发送两次。

即:在一个字符串中发送所有内容。

void SendPackage(const SOCKET sock, const std::string package)
{
int length = package.lenth();
send(sock, std::to_string(length).c_str(), 10, 0);     //Buffer length is 10 assuming data length
send(sock, package.c_str(), length, 0);        //will never be greater than 9,999,999,999
}
void ReceivePackage(const SOCKET sock, std::string &package, int bufferLength)
{
std::vector<char> recvBuffer(10);
int length, bytesProcessed;
recv(sock, &recvBuffer[0], 10, 0); //Receiving length
length = atoi(&recvBuffer[0]);
recvBuffer.resize(length);
for (int i = 0; i < length; i += bytesProcessed)
{
bytesProcessed = recv(sock, &recvBuffer[0] + i, bufferLength, 0);
if (bytesProcessed < 0) break;
}
package = &recvBuffer[0];
}
send(sock, std::to_string(length).c_str(), 10, 0);

这是 UB。你告诉它数据有 10 个字节,但这是不正确的。除此之外,没有必要将你的int转换为字符串,然后发送字符串。刚刚发送了int,为了避免任何平台不兼容,我建议使用固定大小的类型:

std::int32_t length = package.length();
send(sock, &length, sizeof(length), 0);

在接收端,您必须确保实际等待所有字节都在那里。您不能简单地调用recv并假设它为您提供所需的所有字节。你需要在循环中调用它并检查它的返回值,它告诉你你得到了多少字节。要接收length,您需要将适当数量的字节读取到缓冲区中,然后将该缓冲区重新解释为您选择的类型(例如std::int32_t.

此外,您应该确保 int 的字节序正确。对网络数据使用大端序是事实上的标准,但归根结底,这取决于您。不是标准(afaik(的一部分,但在常见平台上可用的是辅助函数htonlntohl,它们代表"主机到网络,长"和"网络到主机,长"。它们获取并返回一个std::int32_t,您可以简单地使用它们来确保字节序对双方都有效。

寄件人:

std::int32_t length = htonl(package.length());
send(sock, &length, sizeof(length), 0);

接收器:

// after successfully reading all bytes for the length value into an adequately sized buffer:
std::int32_t length = ntohl(*reinterpret_cast<std::int32_t*>(buffer));

就套接字接口而言,您不会发送两次。套接字只是通过一个或多个send调用将您塞入一端的所有内容,并在自己的时间内将其发送出去(我假设您在第一次调用时不会超过套接字缓冲区,这是一个相当安全的假设(。同样,您无需将recv呼叫与send呼叫进行匹配。你可以一次recv全部,然后再分解,但实际上,这样做没有太大的收获。

因此,无论您是先打包字符串然后发送,还是send两次调用,这真的是一种洗涤。创建长度连接到开头的新字符串所需的时间和 RAM 不会比只调用两次send更有效。

但是,您绝对应该将长度作为它出现int发送,而不是作为字符串发送。这样它将始终占用sizeof(int)个字节。10的缓冲区长度通常不为真,并导致读取字符串的末尾。例如:

send(sock, &length, sizeof(length), 0);

recv(sock, &length, sizeof(length), 0); //Receiving length