如何使用 C++ 在 TCP 客户端服务器中迭代循环

How to iterate a loop in a TCP client server using c++

我是 TCP client/server 通信的新手。我正在尝试在服务器中循环发送输出并在客户端中接收它。

我的问题是,我在客户端获取随机值作为输出。

我已经分享了我的服务器和客户端片段:

server.cpp

string r_n, r_n1, r_n2, r_n3, r_n4, r_n5, r_n6, r_n7, r_n8, r_n9;

for (result::const_iterator c = R.begin(); c != R.end(); ++c) {

    r_n =  c[0].as<int>();
    r_n1 = c[1].as<string>();

    r_n2 = c[2].as<string>();
    r_n3 = c[3].as<string>();
    r_n4 = to_string(c[4].as<long long int>());
    r_n5 = c[5].as<string>();
    r_n6 = c[6].as<string>();
    r_n7 = c[7].as<string>();
    r_n8 = to_string(c[8].as<int>());
    r_n9 = to_string(c[9].as<int>());

    send(serverSocket, r_n.c_str(), sizeof(r_n), 0);
    send(serverSocket, r_n1.c_str(), sizeof(r_n1), 0);
    send(serverSocket, r_n2.c_str(), sizeof(r_n2), 0);
    send(serverSocket, r_n3.c_str(), sizeof(r_n3), 0);
    send(serverSocket, r_n4.c_str(), sizeof(r_n4), 0);
    send(serverSocket, r_n5.c_str(), sizeof(r_n5), 0);
    send(serverSocket, r_n6.c_str(), sizeof(r_n6), 0);
    send(serverSocket, r_n7.c_str(), sizeof(r_n7), 0);
    send(serverSocket, r_n8.c_str(), sizeof(r_n8), 0);
    send(serverSocket, r_n9.c_str(), sizeof(r_n9), 0);
}

client.cpp

int i = 0;
while (i < 4)
{
    recv(TCPClientSocket, RecvBuffer, sizeof(RecvBuffer), 0);
    recv(TCPClientSocket, RecvBuffer1, sizeof(RecvBuffer1), 0);
    recv(TCPClientSocket, RecvBuffer2, sizeof(RecvBuffer2), 0);
    recv(TCPClientSocket, RecvBuffer3, sizeof(RecvBuffer3), 0);
    recv(TCPClientSocket, RecvBuffer4, sizeof(RecvBuffer4), 0);
    recv(TCPClientSocket, RecvBuffer5, sizeof(RecvBuffer5), 0);
    recv(TCPClientSocket, RecvBuffer6, sizeof(RecvBuffer6), 0);
    recv(TCPClientSocket, RecvBuffer6, sizeof(RecvBuffer6), 0);
    recv(TCPClientSocket, RecvBuffer7, sizeof(RecvBuffer7), 0);
    recv(TCPClientSocket, RecvBuffer8, sizeof(RecvBuffer8), 0);
    recv(TCPClientSocket, RecvBuffer9, sizeof(RecvBuffer9), 0);

    cout << "\t" << RecvBuffer << "\t" << RecvBuffer1 << "\t" << RecvBuffer2 << "\t" << RecvBuffer3;
    cout << "\t" << RecvBuffer4 << "\t" << RecvBuffer5 << "\t" << RecvBuffer6 << "\t" << RecvBuffer7 << "\t" << RecvBuffer8 << "\t" << RecvBuffer9 << endl;
    cout << endl;

    i++;
}

客户端输出:

102     AC      First   shek 9944833930      Chennai      2022-05-21      6       1000

TCP 是一个字节流,它没有消息边界的概念,所以你必须明确数据本身的数据大小。在发送数据本身之前发送数据的大小,或者在数据之后发送一个唯一的终止符。

你的 string 数据是 variable-length,但你没有以任何方式分隔你的字符串,所以客户端无法知道实际发送了多少数据,甚至是哪些数据属于哪个字符串。

当通过 send() 发送 string 时,sizeof() 是错误的缓冲区大小。您需要改用字符串的 size() 方法。您还需要注意 send() 的 return 值,因为它告诉您实际接受发送的字节数,可能是 (和 经常) 小于请求的字节数。与 recv() 相同。因此,您需要在循环中调用这两个函数,直到您拥有 sent/received 预期的字节数。此外,recv() 的输出不是 null-terminated,但您的代码期望它是。

话虽如此,请尝试更类似的方法:

server.cpp

void sendRaw(int socket, const void *data, size_t size)
{
    const char *ptr = reinterpret_cast<const char*>(data); 
    while (size > 0)
    {
        int numSent = send(socket, ptr, size, 0);
        if (numSent < 0) throw ...;
        ptr += numSent;
        size -= numSent;
    }
}

void sendUInt32(int socket, uint32_t value)
{
    value = htonl(value);
    sendRaw(socket, &value, sizeof(value));
}

void sendString(int socket, const string &str)
{
    uint32_t size = str.size();
    sendUInt32(socket, size);
    sendRaw(socket, str.c_str(), size);
}

...

string n_r[10];

sendUInt32(serverSocket, R.size());

for (result::const_iterator c = R.begin(); c != R.end(); ++c) {

    n_r[0] = to_string(c[0].as<int>();
    n_r[1] = c[1].as<string>();
    n_r[2] = c[2].as<string>();
    n_r[3] = c[3].as<string>();
    n_r[4] = to_string(c[4].as<long long int>());
    n_r[5] = c[5].as<string>();
    n_r[6] = c[6].as<string>();
    n_r[7] = c[7].as<string>();
    n_r[8] = to_string(c[8].as<int>());
    n_r[9] = to_string(c[9].as<int>());

    for(int i = 0; i < 10; ++i) {
        sendString(serverSocket, n_r[i]);
    }
}

client.cpp

void recvRaw(int socket, void *data, size_t size)
{
    char *ptr = reinterpret_cast<char*>(data); 
    while (size > 0)
    {
        int numRecvd = recv(socket, ptr, size, 0);
        if (numRecvd <= 0) throw ...;
        ptr += numRecvd;
        size -= numRecvd;
    }
}

uint32_t recvUInt32(int socket)
{
    uint32_t value;
    recvRaw(socket, &value, sizeof(value));
    return ntohl(value);
}

string recvString(int socket)
{
    string str;
    uint32_t size = recvUInt32(socket);
    if (size > 0)
    {
        str.resize(size);
        recvRaw(socket, str.data(), size);
    }
    return str;
}

...

string r_n[10];
uint32_t count = recvUInt32(TCPClientSocket);

for(uint32_t i = 0; i < count; ++i)
{
    for (int i = 0; i < 10; ++i) {
        r_n[i] = recvString(TCPClientSocket);
    }

    for (int i = 0; i < 10; ++i) {
        cout << '\t' << r_n[i];
    }
    cout << endl << endl;
}

也就是说,您的一些输出字段最初是整数而不是字符串,因此最好将它们作为整数而不是字符串发送,例如:

server.cpp

void sendRaw(int socket, const void *data, size_t size)
{
    const char *ptr = reinterpret_cast<const char*>(data); 
    while (size > 0)
    {
        int numSent = send(socket, ptr, size, 0);
        if (numSent < 0) throw ...;
        ptr += numSent;
        size -= numSent;
    }
}

void sendUInt32(int socket, uint32_t value)
{
    value = htonl(value);
    sendRaw(socket, &value, sizeof(value));
}

void sendInt32(int socket, int32_t value)
{
    value = htonl(value);
    sendRaw(socket, &value, sizeof(value));
}

void sendInt64(int socket, int64_t value)
{
    value = htonll(value); // or whatever equivalent your environment provides
    sendRaw(socket, &value, sizeof(value));
}

void sendString(int socket, const string &str)
{
    uint32_t size = str.size();
    sendUInt32(socket, size);
    sendRaw(socket, str.c_str(), size);
}

...

int n_r, n_r8, n_r9;
string n_r1, n_r2, n_r3, n_r5, n_r6, n_r7;
long long int n_r4;

sendUInt32(serverSocket, R.size());

for (result::const_iterator c = R.begin(); c != R.end(); ++c) {

    n_r  = c[0].as<int>();
    n_r1 = c[1].as<string>();
    n_r2 = c[2].as<string>();
    n_r3 = c[3].as<string>();
    n_r4 = c[4].as<long long int>();
    n_r5 = c[5].as<string>();
    n_r6 = c[6].as<string>();
    n_r7 = c[7].as<string>();
    n_r8 = c[8].as<int>();
    n_r9 = c[9].as<int>();

    sendInt32(serverSocket, n_r);
    sendString(serverSocket, n_r1);
    sendString(serverSocket, n_r2);
    sendString(serverSocket, n_r3);
    sendInt64(serverSocket, n_r4);
    sendString(serverSocket, n_r5);
    sendString(serverSocket, n_r6);
    sendString(serverSocket, n_r7);
    sendInt32(serverSocket, n_r8);
    sendInt32(serverSocket, n_r9);
}

client.cpp

void recvRaw(int socket, void *data, size_t size)
{
    char *ptr = reinterpret_cast<char*>(data); 
    while (size > 0)
    {
        int numRecvd = recv(socket, ptr, size, 0);
        if (numRecvd <= 0) throw ...;
        ptr += numRecvd;
        size -= numRecvd;
    }
}

uint32_t recvUInt32(int socket)
{
    uint32_t value;
    recvRaw(socket, &value, sizeof(value));
    return ntohl(value);
}

int32_t recvInt32(int socket)
{
    int32_t value;
    recvRaw(socket, &value, sizeof(value));
    return ntohl(value);
}

int64_t recvInt64(int socket)
{
    int32_t value;
    recvRaw(socket, &value, sizeof(value));
    return ntohll(value); // or whatever equivalent your environment provides
}

string recvString(int socket)
{
    string str;
    uint32_t size = recvUInt32(socket);
    if (size > 0)
    {
        str.resize(size);
        recvRaw(socket, str.data(), size);
    }
    return str;
}

...

int n_r, n_r8, n_r9;
string n_r1, n_r2, n_r3, n_r5, n_r6, n_r7;
long long int n_r4;

uint32_t count = recvUInt32(TCPClientSocket);

for(uint32_t i = 0; i < count; ++i)
{
    n_r  = recvInt32(TCPClientSocket);
    n_r1 = recvString(TCPClientSocket);
    n_r2 = recvString(TCPClientSocket);
    n_r3 = recvString(TCPClientSocket);
    n_r4 = recvInt64(TCPClientSocket);
    n_r5 = recvString(TCPClientSocket);
    n_r6 = recvString(TCPClientSocket);
    n_r7 = recvString(TCPClientSocket);
    n_r8 = recvInt32(TCPClientSocket);
    n_r9 = recvInt32(TCPClientSocket);

    cout << '\t' << n_r << '\t' << n_r1 << '\t' << n_r2 << '\t' << n_r3 << '\t' << n_r4 << '\t' << n_r5 << '\t' << n_r6 << '\t' << n_r7 << '\t' << n_r8 << '\t' << n_r9 << endl << endl;
}