1

我正在创建一个可以获取包并通过 C++ 将其打印到控制台的程序。我将 char 数组设置为 1024,例如:

char* buffer = new char[1024];

当我收到一条不完全是 1024 字符的消息时,由于数组中的空白空间,我的消息末尾有许多未知字符。我能做些什么?

更多信息(我不知道它是否有用)

套接字由 Java 程序发送

Socket socket = new Socket("127.0.0.1", 27555);

BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
out.write("I am your client :D");
out.flush(); 

服务器由 C++ 控制台应用程序编写

char* recvData = new char[1024];
recv(socket, recvData, strlen(recvData), 0);
cout << recvData << endl;
4

4 回答 4

7

代码存在三个问题:

  • recvData传递给 时被统一化strlen()strlen()当它找到一个空终止字符时确定缓冲区的长度,它可以在缓冲区内或外部。缓冲区的大小(用于终止空字符的减一)应作为要读取的最大字节数传递。
  • 的结果recv()不被查询。recvData即使recv()失败,代码也会使用,这是一个错误。
  • recv()不为空终止缓冲区。

保存结果,recv()如果不-1将其用作recvData插入空终止字符的索引。

或者,因为这是 c++,所以使用std::vector<char>and 为您管理动态内存分配(如果确实需要动态内存分配):

std::vector<char> recvData(1025); // Default initializes all elements to 0.
int result = recv(socket, recvData.data(), recvData.size() - 1);
if (result != -1)
{
    std::cout << recvData.data() << std::endl;
}

请记住,通过套接字发送的数据只是一个字节流,它没有分成不同的消息。这意味着:

out.write("I am your client :D");

一次调用可能无法读取recv(). 相等:

out.write("I am your client :D");
out.write("OK");

可以通过一次调用来读取recv(). 如果需要基于消息的处理,则实现协议是程序员的责任。

于 2013-05-29T10:04:45.337 回答
5

strlen计算字节数,直到'\0'遇到空 ( ) 字符。不能保证单个recv调用返回的数据将被 nul 终止,因此您需要检查返回的字节数,然后添加您自己的终止符。

char* recvData = new char[1024];
int bytes = recv(socket, recvData, 1023, 0);
if (bytes == -1) {
    cout << "error on recv" << endl;
}
else {
    recvData[bytes] = '\0';    
    cout << recvData << endl;
}
于 2013-05-29T10:03:41.357 回答
1

recvData不是null 终止的,因此strlen()在这种情况下,结果是未定义的。您必须执行以下操作:

int len = 1024;
char *recvData = new char[len + 1];
int lenRead = recv(socket, recvData, len, 0);
if (lenRead < len)
    recvData[lenRead] = '\0';
else
    recvData[len] = '\0'; 
cout << recvData << endl;
于 2013-05-29T10:09:47.530 回答
0

这不是很明显吗?:)

只需先发送字符串的长度或“正确”终止字符串(通过在\0字符串末尾发送 a ;我猜这是 Java 在这里没有做的事情)。

但总的来说,无论如何您都应该包含“数据包长度”,因为您可能希望在写入缓冲区之前确保有足够的可用空间(strlen()在未初始化的数组上使用通常是一个坏主意)。

于 2013-05-29T10:04:31.653 回答