简体   繁体   中英

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. 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.

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:

  • sizeof numberString is the wrong number of bytes to send. That is the compile-time size of the string class, not the run-time byte size of the character data it points to.

  • 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. 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() . 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:

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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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