客户端服务器通信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
的返回值完全被忽略,根本不检查。
所有套接字系统调用都可能失败,每个套接字系统调用send
、recv
和所有其他的都可能失败。此外,即使成功,recv
也不会向您提供任何保证,send
的所有内容都将在一个镜头中成为recv
ed .
例如,如果 send
发送了 10 个字节,则对 recv
的第一次调用可能会返回 1 或 5,表示只有前一个或五个字节会立即被 recv
ed。您不保证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(服务器)中收到的 python(客户端)“解包”数据包?
Java TCP/IP SocketTCP Socket通信中由read返回值造成的的死锁问题(含代码)