繁体   English   中英

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

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

我有一个连接到客户端并执行以下通信的服务器:

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

客户端执行相同的通信,但相反:

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

问题是服务器有时(在循环此通信 100 多次之后)没有收到来自客户端的第二条发送的消息并挂起。 客户端从服务器接收消息从来没有问题,它总是服务器挂起。 服务器打印:

Sending: 344486269
Sending: 7
Received: 0

然后不会终止,所以我知道它正在等待永远不会出现的第二个值。 客户端打印:

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

所以我知道客户端成功地执行了它的send()命令。

什么可能导致服务器无法正确接收第二条消息?

void send(int sockt, long number) ,您对write()调用是错误的,原因如下:

  • sizeof numberString是要发送的错误字节数。 那是string类的编译时大小,而不是它指向的字符数据的运行时字节大小。

  • 您没有以任何方式分隔发送的数据,让接收者知道数据何时结束。 发送变长数据时,必须要么在发送数据前发送数据长度,要么在数据后发送一个唯一的终止符。

  • 您没有考虑write()发送的字节数可能少于请求的字节数。 您必须在循环中调用它,直到所有所需的字节都已完全发送。

同样,在long receive(int sockt) ,您也有与recv()相关的类似问题。 您只调用一次,而不管发送的数据的大小。 并且您忽略了它的返回值以了解实际读取了多少字节。

你需要更像下面的东西:

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

但是,更好的解决方案是简单地以固定大小的二进制格式而不是可变长度字符串发送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