简体   繁体   English

C++ 服务器 recv() 命令并不总是从客户端接收 send()

[英]C++ Server recv() command does not always receive send() from client

I have a server that connects to a client and executes the following communication:我有一个连接到客户端并执行以下通信的服务器:

void communicate(promise<long> && divisions, promise<long> && result, int sockt, long number, long prime) {
    send(sockt, number);
    send(sockt, prime);
    long div = receive(sockt);
    long res = receive(sockt);
    divisions.set_value(div);
    result.set_value(res);
}

void send(int sockt, long number) {
    string numberString;
    stringstream strstream;
    strstream << number;
    strstream >> numberString;
    cout << "Sending: " << number << endl;
    write(sockt, numberString.c_str(), sizeof numberString);
}

long receive(int sockt) {
    // receive string
    const unsigned int MAX_BUF_LENGTH = 1024;
    std::vector<char> buffer(MAX_BUF_LENGTH);
    std::string rcv;
    recv(sockt, &buffer[0], buffer.size(), 0);
    rcv.append(buffer.cbegin(), buffer.cend());

    //convert string to long
    string::size_type sz = 0;
    long val = stoll(rcv, &sz, 0);
    cout << "Received: " << val << endl;

    return val;
}

The client performs the same communication but in reverse:客户端执行相同的通信,但相反:

void communicate(){
    string number = receive(sockt);
    string prime = receive(sockt);
    // do stuff to the data
    send(sockt, divisions);
    send(sockt, val);
}

The problem is the server sometimes (after looping this communication 100+ times) does not receive the second sent message from the client and hangs.问题是服务器有时(在循环此通信 100 多次之后)没有收到来自客户端的第二条发送的消息并挂起。 The client never has trouble receiving a message from the server its always the server hanging.客户端从服务器接收消息从来没有问题,它总是服务器挂起。 The server prints:服务器打印:

Sending: 344486269
Sending: 7
Received: 0

Then does not terminate so I know its awaiting the second value which never comes.然后不会终止,所以我知道它正在等待永远不会出现的第二个值。 The client prints:客户端打印:

Received: 344486269
Received: 7
Sending: 0
Sending: 344486269

So I know the client successfully performs its send() commands.所以我知道客户端成功地执行了它的send()命令。

What could be causing the server to not properly receive the second message?什么可能导致服务器无法正确接收第二条消息?

In void send(int sockt, long number) , your call to write() is faulty, for several reasons:void send(int sockt, long number) ,您对write()调用是错误的,原因如下:

  • sizeof numberString is the wrong number of bytes to send. sizeof numberString是要发送的错误字节数。 That is the compile-time size of the string class, not the run-time byte size of the character data it points to.那是string类的编译时大小,而不是它指向的字符数据的运行时字节大小。

  • you are not delimiting the sent data in any way that allows the receiver to know when the data ends.您没有以任何方式分隔发送的数据,让接收者知道数据何时结束。 When sending variable length data, you MUST either send the data length before sending the data, or else send a unique terminator after the data.发送变长数据时,必须要么在发送数据前发送数据长度,要么在数据后发送一个唯一的终止符。

  • you are not accounting for the possibility that write() can send fewer bytes than requested.您没有考虑write()发送的字节数可能少于请求的字节数。 You must call it in a loop until all of the desired bytes have been fully sent.您必须在循环中调用它,直到所有所需的字节都已完全发送。

Likewise, in long receive(int sockt) , you have similar issues related to recv() .同样,在long receive(int sockt) ,您也有与recv()相关的类似问题。 You are calling it only one time without any regard to the size of the data being sent.您只调用一次,而不管发送的数据的大小。 And you are ignoring its return value to know how many bytes were actually read.并且您忽略了它的返回值以了解实际读取了多少字节。

You need something more like the following instead:你需要更像下面的东西:

void send(int sockt, long number) {
    ostringstream oss;
    oss << number;
    string numberString = oss.str();
    // or simply:
    // string numberString = to_string(number);

    cout << "Sending: " << numberString << endl;

    const char *ptr = numberString.c_str();
    string::size_type size = numberString.size() + 1;
    do {
        int written = write(sockt, ptr, size);
        if (written < 0) {
            // error handling as needed...
            return;
        }
        ptr += written;
        size -= written;
    }
    while (size > 0);
}

long receive(int sockt) {
    // receive string
    char ch;
    std::string rcv;
    do {
        if (recv(sockt, &ch, 1, 0) <= 0) {
            // error handling as needed...
            return -1;
        }
        if (ch == '\0') break;
        rcv += ch;
    }
    while (true);

    //convert string to long
    string::size_type sz = 0;
    long val = stoll(rcv, &sz, 0);
    cout << "Received: " << val << endl;

    return val;
}

However, a much better solution would be to simply send the long data in a fixed sized binary format instead of as a variable length string:但是,更好的解决方案是简单地以固定大小的二进制格式而不是可变长度字符串发送long数据:

void send(int sockt, long number) {
    uint32_t tmp = htonl(number);
    cout << "Sending: " << number << endl;
    char *ptr = reinterpret_cast<char*>(&tmp);
    size_t size = sizeof(tmp);
    do {
        int written = write(sockt, ptr, size);
        if (written < 0) {
            // error handling as needed...
            return;
        }
        ptr += written;
        size -= written;
    }
    while (size > 0);
}

long receive(int sockt) {
    // receive long
    uint32_t tmp;
    char *ptr = reinterpret_cast<char*>(&tmp);
    size_t size = sizeof(tmp);
    do {
        int recvd = recv(sockt, ptr, size, 0);
        if (recvd <= 0) {
            // error handling as needed...
            return -1;
        }
        ptr += recvd;
        size -= recvd;
    }
    while (size > 0);

    long val = ntohl(tmp);
    cout << "Received: " << val << endl;

    return val;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM