客户端服务器通信c ++中收到的垃圾值

Posted

技术标签:

【中文标题】客户端服务器通信c ++中收到的垃圾值【英文标题】:Garbage value received in client server communication c++ 【发布时间】:2021-08-05 23:26:25 【问题描述】:

我试图在 Windows 上编写一个简单的客户端服务器程序。我的服务器端代码如下所示。

#include <iostream>
#include <windows.h>
#include <winsock2.h>
#include <stdlib.h>
#include <stdio.h>

using namespace std;

int main()

    WSADATA WSAData;
    SOCKET serverSock, clientSock;
    SOCKADDR_IN serverAddr, clientAddr;

    WSAStartup(MAKEWORD(2,0),&WSAData);
    serverSock=socket(AF_INET,SOCK_STREAM,0);

    serverAddr.sin_addr.s_addr=INADDR_ANY;
    serverAddr.sin_family=AF_INET;
    serverAddr.sin_port=htons(5555);

    bind(serverSock,(SOCKADDR *)&serverAddr, sizeof(serverAddr));
    listen(serverSock,0);
    std::cout<<"Listening for incoming connections \n";

    char buffer[1024];
    //memset(buffer,0,sizeof(buffer));
    int clientAddrsize= sizeof(clientAddr);
    if(clientSock = ( accept(serverSock,(SOCKADDR *)&clientAddr, &clientAddrsize ) != INVALID_SOCKET) )
    
        std::cout<<"Client connected \n";
        recv(clientSock,buffer,int(strlen(buffer)),0);
        std::cout<<"Client Says: " << buffer <<"\n" ;
        Sleep(10000);
        //memset(buffer,0,sizeof(buffer));
        closesocket(clientSock);
        closesocket(serverSock);
        WSACleanup();
    
    return 0;

客户端代码如下:

#include <iostream>
#include <winsock2.h>
#include <stdlib.h>
#include <stdio.h>

using namespace std;

int main()

    WSADATA WSAData;
    SOCKET clientSock;
    SOCKADDR_IN addr;

    WSAStartup(MAKEWORD(2,0),&WSAData);
    clientSock=socket(AF_INET,SOCK_STREAM,0);

    addr.sin_addr.s_addr=inet_addr("127.0.0.1");
    addr.sin_family=AF_INET;
    addr.sin_port=htons(5555);

    connect(clientSock,(SOCKADDR *)&addr,sizeof(addr));
    std::cout <<"Connected to the server \n";
    //memset(buffer,0,sizeof(buffer));
    char buffer[1024]='h','e','l','l','o','.','\0';
    send(clientSock,buffer,int(strlen(buffer)),0);
    std::cout<<"Message sent \n" ;
    Sleep(10000);
    closesocket(clientSock);
    WSACleanup();
    std::cout<<"Socket closed \n";
    return 0;

我在服务器端看到以下输出:

 Listening for incoming connections
 Client connected
 Client Says: R☺

我期待的是Client Says: Hello.。不知道为什么我得到垃圾值。

谢谢

【问题讨论】:

“垃圾”值几乎总是取决于使用未初始化的数据(局部变量或数组元素);或者不添加、跳过或不计算字符串空终止符。 顺便说一下,char buffer[1024]='h','e','l','l','o','.','\0';char buffer[1024]="hello.";完全一样 您需要始终捕获 recv() 返回的值并对其进行适当的处​​理。如果不这样做,您将无法知道 recv() 实际写入本地缓冲区的字节数。 (它可能比您要求的字节少) 例如:send(clientSock,buffer,int(strlen(buffer)),0);不会发送buffer 的空终止符。而recv(clientSock,buffer,int(strlen(buffer)),0); 使用buffer未初始化(因此是不确定的,或者如果你愿意的话是垃圾)内容来计算数组的大小。所以你有我之前列出的两个问题的组合。 另外,将 strlen(buffer) 作为 recv() 的最后一个参数传入没有多大意义,因为 strlen() 读取其参数指向的字节以查看字符串的长度,并且在您调用 recv() 时,尚未收到字符串,因此这是不可能的。您可能想要传递 sizeof(buffer) 。 【参考方案1】:
char buffer[1024];

这在自动范围内声明了一个本地 char 数组。该数组没有初始化任何东西,并且包含随机垃圾。

recv(clientSock,buffer,int(strlen(buffer)),0);

这会将buffer 传递给strlen。但是,buffer 包含垃圾,这是未定义的行为,最终结果可能是随机的,介于此时立即崩溃或来自 strlen 的一些奇怪的返回值之间的任何事情。

另外,recv 的返回值完全被忽略,根本不检查

所有套接字系统调用都可能失败,每个套接字系统调用sendrecv 和所有其他的都可能失败。此外,即使成功,recv 也不会向您提供任何保证send 的所有内容都将在一个镜头中成为recved .

例如,如果 send 发送了 10 个字节,则对 recv 的第一次调用可能会返回 1 或 5,表示只有前一个或五个字节会立即被 recved。您不保证recv 将一次性收到这 10 个字节。否则,recv 将(显然)需要再次调用以接收其余消息。

您需要解决所有这些问题才能拥有可靠的客户端/服务器应用程序:

    检查所有系统调用的返回值。我所说的关于recv 的所有内容也适用于send。尝试send 10 字节可能会返回 7,表示仅发送了前 7 个字节,然后您必须实现适当的逻辑来发送剩余的字节。

    修复未定义的行为,将未初始化的值传递给strlen

【讨论】:

感谢@Sam 提供详细信息。非常欣赏它。您能否指出一些实际的实现,我可以在其中看到有关如何处理由 brotobuf 序列化并发送的数据的参考代码,并且可以读取。或任何有意义的数据交换示例,以便我可以从中借鉴或指向我的教程。互联网上的大多数都没有显示如何正确处理和读取 recv 调用中的 tcp 数据包。 我同意:不能从随机的 Google 搜索或某些小丑上传到 Youtube 的随机视频中学习 C、C++ 或任何类型的技术编程主题。学习高级技术主题的唯一方法是借助一本好的教科书。经典教科书是 Stevens 的“Unix Network Programming”,但我认为它现在有点过时了。但是如果你搜索这本书,你应该会找到一些其他相当不错的书供参考。

以上是关于客户端服务器通信c ++中收到的垃圾值的主要内容,如果未能解决你的问题,请参考以下文章

C#定时器接收定时发送和处理接收socket异步通信,接收值放在静态变量里,有时候收到的数据不完整。

c中客户端-服务器通信失败

如何从 C(服务器)中收到的 python(客户端)“解包”数据包?

Java TCP/IP SocketTCP Socket通信中由read返回值造成的的死锁问题(含代码)

Linux C语言 C/S程序,客户端发送的数据和服务器端接收到的数据不一样,求解

使用C语言实现服务器/客户端的TCP通信