通过 Socket C++ 发送长字符串

Posted

技术标签:

【中文标题】通过 Socket C++ 发送长字符串【英文标题】:Sending a long String over a Socket C++ 【发布时间】:2016-06-03 05:10:12 【问题描述】:

我在使用套接字进行一些基本客户端 服务器通信时遇到了一个奇怪的问题。

服务器通过使用ostringstream 对象和一些简单的换行符和空格格式将数据转储到一个长字符串中来打包包含玩家信息的结构数组,然后通过套接字将该字符串发送到客户端以显示给播放器。

当被打包的一个或多个结构中的“名称”字段超过 4 个字符时,就会出现问题;如果是这种情况,则每个“名称”字段中包含 5 个以上字符的第 4 个字符之后的每个字符都将在字符串 AFTER* 发送到客户端后的一行中重复。

*打包后的字符串在服务端总是能正常显示。

下面是相关代码和两张服务器端和客户端的截图,一张显示错误,一张没有。

服务器代码:

struct leader_board_pos

    string name;
    int score;
;

leader_board_pos leader_board[num_players]; 

....

// Package and send the current leaderboard to the client 
int i = 0;
string leader_board_package;
string dubspace = "  ";
ostringstream oss;

cout << "Package leader board > "; cin.ignore();

leader_board_package = "Leader Board: \n";
while(i < num_leaders)

    oss << leader_board[i].name << dubspace << leader_board[i].score << endl;
    leader_board_package += oss.str();
    oss.str(string());
    i++;


cout << leader_board_package; cin.ignore();

bytes_sent = send(clientSock, leader_board_package.c_str(), leader_board_package.length(), 0);

if (bytes_sent != leader_board_package.length())

    cout << "Server Message: Communication error..." << endl;
    return;

客户代码:

const int MAX_BUFF_LENGTH = 4096;

...

//Get and display Leaderboard
int bytes_recv = 0;
vector<char> leader_board_buffer(MAX_BUFF_LENGTH);
string leader_board_package;

do 

    bytes_recv = recv(sock, leader_board_buffer.data(), MAX_BUFF_LENGTH, 0);

    if (bytes_recv == -1)
    
        cout << "Communication error...";
        return 0;
    
    else
    
        leader_board_package.append(leader_board_buffer.begin(), leader_board_buffer.end());
    

 while (bytes_recv == MAX_BUFF_LENGTH);

cout << endl << endl << leader_board_package; cin.ignore(); 

屏幕截图,突出显示的相关部分:

Screenshot with Error

Screenshot without Error

除非我遗漏了其他内容,否则我 99% 确定错误出现在客户端的 do-while 接收循环中,因为字符串在服务器端打印时会正确显示。我无法想象会导致这样一个特定错误的原因,因为它只是发送了一个长字符串。

【问题讨论】:

您是否尝试过禁用结构填充。因为如果结构填充是由编译器在内部完成的,就会出现问题。由于字符串在服务器端正确显示,但在客户端出现问题。自从您使用 ostringstream 以来,还有一件事请检查缓冲区清除以及与此相关的任何问题。 您的接收循环不正确。你必须加起来bytes_recv,而不是每次迭代都替换它。像bytes_recv += recv(.. 或更好的中间变量,所以你可以每次都对照-1 检查它。然后while 条件应该是!= MAX_BUFF_LENGTH,而不是==。但是你不发送MAX_BUFF_LENGTH字节,所以也许你想先发送一个带有消息长度的标头,这样客户端就知道要接收多少。 【参考方案1】:
leader_board_package.append(leader_board_buffer.begin(), leader_board_buffer.end());

这是错误的。缓冲区只包含bytes_recv 价值的接收数据。

while (bytes_recv == MAX_BUFF_LENGTH);

如果您将消息从片段中组合起来,则需要在某处将它们的长度相加。

另外,

if (bytes_sent != leader_board_package.length())

这也是错误的。不要依赖send 能够一次发送整个数组。正确的发送方式是以循环接收的方式循环。

目前还不清楚您的邮件应该有多大。如果它是可变的,您需要将它与消息一起传输。如果是 MAX_BUFF_LENGTH,则需要 send() 这个确切的字节数。您不能依赖通过 TCP 一次性发送或接收的消息。

【讨论】:

以上是关于通过 Socket C++ 发送长字符串的主要内容,如果未能解决你的问题,请参考以下文章

C++ 通过套接字发送字符串

C ++单个字符未通过套接字发送

C#通过Socket同时发送字符串和视频流

通过套接字发送字符串(python)

QByteArray::number(int) 只有两个字节长

将字符串从 C# 发送到 C++ dll 文件