C ++ Socket recv没有收到正确的字节数?

时间:2014-12-17 21:55:28

标签: c++ sockets

我对C ++很陌生,但我正在尝试学习一些TCP套接字编码的基础知识。无论如何,我已经能够发送和接收消息了,但是我希望在数据包的长度前面加上数据包的长度(就像我过去在C#应用程序中所做的那样),所以当我的窗口获得FD_READ命令时,我有以下代码只读取数据包的前两个字节用作短整数。

char lengthBuffer[2];

int rec = recv(sck, lengthBuffer, sizeof(lengthBuffer), 0);

short unsigned int toRec = lengthBuffer[1] << 8 | lengthBuffer[0];

让我感到困惑的是,在收到数据包之后,我们会感到困惑。变量,表示读取的字节数是一个,而不是两个,如果我将lengthBuffer设为三个字符而不是两个,则读取三个字节,但如果它是四个字节,则它还读取三个(仅奇数) 。我无法判断我是否在这里犯了一些非常愚蠢的错误,或者从根本上误解了语言或API的某些部分。我知道recv不能保证读取任意数量的字节,但如果它只有两个,则不应该进行多次读取。

3 个答案:

答案 0 :(得分:5)

由于您无法假设有多少数据可用,因此您需要不断读取套接字,直到获得所需金额为止。这样的事情应该有效:

ssize_t rec = 0;
do {
    int result = recv(sck, &lengthBuffer[rec], sizeof(lengthBuffer) - rec, 0);
    if (result == -1) {
        // Handle error ...
        break;
    }
    else if (result == 0) {
        // Handle disconnect ...
        break;
    }
    else {
        rec += result;
    }
}
while (rec < sizeof(lengthBuffer));

答案 1 :(得分:1)

流式套接字:

套接字通常以流式方式使用:您将收到所有已发送的数据,但不一定全部收到。您也可以接收数据。

你发送长度的方法是有效的:一旦你收到长度,你就可以加载一个缓冲区,如果需要连续读取,直到你得到你想要的一切。因此,您必须循环接收,并定义如何处理接收的额外字节的策略。

Datagramme(面向数据包)套接字:

如果您的应用程序确实是面向数据包的,您可以考虑通过请求linuxwindows socket(),SOCK_DGRAM或更好的SOCK_SEQPACKET套接字类型来创建数据表套接字。

二进制大小数据的风险:

请注意,您发送和接收大小数据的方式可能是不对称的。因此,如果在具有不使用相同endian-ness的CPU /架构的机器之间发送和接收,则会产生重大风险。您可以找到here有关如何使代码平台/字节序无关的一些提示。

答案 2 :(得分:0)

TCP套接字是基于流的,而不是数据包(我假设您使用TCP,因为在数据中发送数据包的长度在UDP中没有任何意义)。您一次收到的字节数不会发送太多金额。例如,您可以发送10个字节,但接收器可能会收到1 + 2 + 1 + 7或任何组合。您的代码必须处理它,能够部分接收数据并在获得足够数据时做出反应(这就是您发送数据包长度的原因)。