【问题标题】:Winsock sends additional dataWinsock 发送附加数据
【发布时间】:2012-02-19 04:34:32
【问题描述】:

我正在用 Winsock 用 C++ 编写一个小型客户端/服务器应用程序,但我无法解释正在发生的一些事情。 我编写了 2 个通过 TCP 连接发送/接收所有数据的基本函数。

bool sending(SOCKET source, char* buff, int size, int flags = 0)
{
    int sent = 0;
    int totalst = 0;
    int total = size;
    while(totalst != total)
    {
        sent = send(source, buff+totalst, size-totalst, flags);
        if(sent > 0)
        {
            totalst += sent;
        }
        if(sent == SOCKET_ERROR)
        {
            return false;
        }       
    }   
    return true;
}

bool receive(SOCKET source, char* buff, int size, int flags = 0)
{
    int rec = 0;
    int totalrc = 0;
    int total = size;
    while(totalrc != total)
    {
        rec = recv(source, buff+totalrc, size-totalrc, flags);
        if(rec > 0)
        {
            totalrc += rec;
        }
        if(rec == SOCKET_ERROR)
        {
            return false;
        }
    }
    return true;
}

服务器发送一个整数,其中包含将跟随它的数据块的大小。在我的例子中,这个数据块的大小不应该改变,它应该总是 92600 字节,但有时客户端会收到 92604字节代替。奇怪的是,如果我在发送块大小和块本身(带睡眠)后让服务器等待,它总是会发送我所期望的..

int i=0;                    
while(i < 100)
{
    i++;
    dat = getData();                                
    len = sizeof(dat);
    sending(source, (char*)&len, sizeof(len));
    sending(source, dat, len);
    Sleep(200);    
}

客户端会因为延迟而接收到不正确的字节值吗? 有没有办法解决这个问题? 任何帮助表示赞赏!

【问题讨论】:

  • 您已经接受了一个答案。但是我刚刚指出了您代码中的两个错误,这些错误可能与您所看到的内容有关,因为 todda 正在谈论什么。请参阅下面的答案。
  • 谢谢!是的,没有人已经在评论中指出了这一点,但他很快就把它删除了。我只是忘记更新我的问题了。

标签: c++ sockets client-server winsock send


【解决方案1】:

考虑这个例子:

char *x = "!";
send(socket, x, 1); // destination, buffer, size
send(socket, x, 1);
send(socket, x, 1);
send(socket, x, 1);

您希望在这里发生什么?

char buffer[4];
recv(socket, buffer, 4); // source, buffer, size

实际上,四个send发送的数据可以被一个recv接收。您无法保证如果您向send 发出n 调用,您将向recv 发出n 调用以接收所有数据。

正如 nos 所评论的,TCP 没有实现消息边界。那是你的工作,在应用层。 Winsock 不会发送额外的数据,你会这样做。

【讨论】:

  • 这是开发人员在使用套接字时所犯的最大错误之一——假设 recv() 将在客户端调用“发送”的相同分块块中传递数据。很多时候,它似乎只是以这种方式工作,而且代码通常是这样部署的——当它开始在不同的环境中运行时,这会产生微妙的错误。
【解决方案2】:

您的发送和接收功能都有错误。

您正确地跟踪发送/接收的总字节数,以便正确退出循环,但您忘记在后续调用发送/接收时调整“buff”和“size”的值。如果要发送的缓冲区必须通过多次发送调用来传输,那么您将发送错误的数据。

同样,如果需要多次调用“recv”,您将覆盖在缓冲区开始处复制的数据。

应该是:

sent = send(source, buff+totalst, size-totalst, 0);

recv 情况也是如此:

rec = recv(source, buff + totalrc, size-totalrc, 0);

我不确定这是否会导致您的问题,但我有一种感觉,当 todda 指出的情况属实时,您的数据流会被此错误破坏。

有意义吗?此外,您应该准备好处理 recv() 将返回 0 的情况。

我希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-25
    • 1970-01-01
    • 1970-01-01
    • 2017-07-22
    • 1970-01-01
    • 2020-08-17
    • 1970-01-01
    相关资源
    最近更新 更多