【问题标题】:server client sending receiving structure via raw data errors C++服务器客户端通过原始数据错误发送接收结构 C++
【发布时间】:2018-09-09 17:28:35
【问题描述】:

我正在通过 TCP/IP 为结构(在我的情况下为“帧”)执行发送和接收功能。但是这些功能似乎没有奏效,我找不到我的错误在哪里。我被要求将所有数据存储在 char 数组中并发送,同时接收 char 数组并将它们转换为结构。

struct frame {
int length;
int * body;
int tail;
};


void winsock_client::send_frame(frame f) {
    char * arr;
    char * tx;
    int length = 8 + f.length * sizeof(int);
    arr = new char[length];

    tx = (char*)&f.length; 
    for (int i = 0; i < sizeof(int); i++) {
        arr[i] = *(tx++);
    }

    for (int i = 0; i < f.length; i++) {
        tx =(char*)&f.body[i];

        for (int j = 0; j < sizeof(int); j++) {
            arr[4 + i * sizeof(int) + j] = *(tx++);
        }
    }

        tx = (char*)&f.tail;
    for (int i = 0; i < sizeof(int); i++) {
        arr[4 + f.length * sizeof(int) + i] = *(tx++);
    }

    send(client_socket, arr, sizeof(arr), 0);
}


void winsock_server::receive_frame(frame & f) {
int * rx;
recv(server_socket, rx_buffer, sizeof(rx_buffer), 0);
rx =(int *) &rx_buffer[0];
f.length = *rx;

f.body = new int[f.length];

rx = (int *)&rx_buffer[4];
for (int i = 0; i < f.length; i++) {
    f.body[i] = *(rx++);
}

rx = (int*)&rx_buffer[16];
f.tail = *rx;

}

谁能告诉我我的函数中有哪些错误?

【问题讨论】:

  • int length = 8 + f.length * sizeof(int); -- 是什么让您确定两个int 成员等于8 个字节? Look at this example that shows that sizeof(frame) == 24.
  • 请记住 TCP 是一个数据流。在任何给定的数据包或致电recv 中,您可能会或可能不会获得您要求的所有数据。例如,当您阅读Frame 时,您可能无法获得完整的Frame。检查返回值并继续循环,直到获得所有内容或使用MSG_WAITALL 标志阻止,直到所有内容都到达。
  • sizeof(arr) in send_frame() 不会返回您认为的结果。
  • 是的,我已将 sizeof(arr) 改为 length。还是不行
  • @AndyLin -- 为什么不简单地通过调试检查您发送的内容?您发送的内容是否正确?您将这些数据放在一起,您在哪里进行任何类型的调试以确保您没有发送垃圾或完全错误的数据?

标签: c++ server client winsock raw-data


【解决方案1】:

您没有检查send()recv() 的返回值,以确保您实际上正在发送/接收您期望的所有内容。 TCP 是一种流传输,发送和接收之间没有 1:1 的关系,就像 UDP 中的那样。这两个函数都可以发送/接收比请求更少的字节,所以你需要处理它。

另外,您的 read_frame() 正在使用固定长度的缓冲区来接收数据,但您没有考虑实际发送了多少数据,因此您的缓冲区可能无法接收到完整的帧,或者更糟的是可能会接收到一个比它可以容纳的更大的框架。

代码也很难读。应该重写。

试试类似的方法:

bool sendAll(SOCKET s, const void *buf, int len)
{
    const char *pbuf = (const char*) buf;
    while (len > 0)
    {
        int sent = send(s, pbuf, len, 0);
        if (sent == SOCKET_ERROR)
            return false;
        pbuf += sent;
        len -= sent;
    }
    return true;
}

bool winsock_client::send_frame(const frame &f)
{
    int size = (2 + f.length) * sizeof(u_long);

    char *arr = new char[size];

    // multi-byte integers should always be transmitted in network
    // byte order to avoid any endian issues across machine boundaries...

    u_long *ptr = (u_long*) arr;

    *ptr++ = htonl(f.length);

    for (int i = 0; i < f.length; ++i)
        *ptr++ = htonl(f.body[i]);

    *ptr = htonl(f.tail);

    bool result = sendAll(client_socket, arr, size);

    delete[] arr;

    return result;
}

bool recvAll(SOCKET s, void *buf, int len)
{
    char *pbuf = (char*) buf;
    while (len > 0)
    {
        int recvd = recv(s, pbuf, len, 0);
        if (recvd <= 0) // -1 on error, 0 on disconnect
            return false;
        pbuf += recvd;
        len -= recvd;
    }
    return true;
}

bool winsock_server::receive_frame(frame &f)
{
    u_long temp;

    if (!recvAll(server_socket, &temp, sizeof(temp)))
        return false;
    f.length = ntohl(temp);

    u_long *arr = new u_long[f.length+1];

    if (!recvAll(server_socket, arr, sizeof(u_long) * (f.length + 1)))
    {
        delete[] arr;
        return false;
    }

    f.body = new int[f.length];

    for(int i = 0; i < f.length; ++i)
        f.body[i] = ntohl(arr[i]);

    f.tail = ntohl(arr[f.length]);

    delete[] arr;

    return true;
}

或者,如果您考虑到套接字已经为您进行了自己的内部缓冲,您可以稍微简化代码:

bool sendAll(SOCKET s, const void *buf, int len)
{
    const char *pbuf = (const char*) buf;
    while (len > 0)
    {
        int sent = send(s, pbuf, len, 0);
        if (sent == SOCKET_ERROR)
            return false;
        pbuf += sent;
        len -= sent;
    }
    return true;
}

bool sendInt(SOCKET s, int value)
{
    // multi-byte integers should always be transmitted in network
    // byte order to avoid any endian issues across machine boundaries...
    u_long temp = htonl(value);
    return sendAll(s, &temp, sizeof(temp));
}

bool winsock_client::send_frame(const frame &f)
{
    if (!sendInt(client_socket, f.length))
        return false;

    for (int i = 0; i < f.length; ++i)
    {
        if (!sendInt(client_socket, f.body[i]))
            return false;
    }

    return sendInt(client_socket, f.tail);
}

bool recvAll(SOCKET s, void *buf, int len)
{
    char *pbuf = (char*) buf;
    while (len > 0)
    {
        int recvd = recv(s, pbuf, len, 0);
        if (recvd <= 0) // -1 on error, 0 on disconnect
            return false;
        pbuf += recvd;
        len -= recvd;
    }
    return true;
}

bool recvInt(SOCKET s, int &value)
{
    u_long temp;
    bool result = recvAll(s, &temp, sizeof(temp));
    if (result) value = ntohl(temp);
    return result;
}

bool winsock_server::receive_frame(frame &f)
{
    if (!recvInt(server_socket, f.length))
        return false;

    f.body = new int[f.length];

    for(int i = 0; i < f.length; ++i)
    {
        if (!recvInt(server_socket, f.body[i]))
        {
            delete[] f.body;
            return false;
        }
    }

    if (!recvInt(server_socket, f.tail))
    {
        delete[] f.body;
        return false;
    }

    return true;
}

【讨论】:

    猜你喜欢
    • 2017-08-20
    • 2019-02-25
    • 2020-07-10
    • 1970-01-01
    • 2013-11-22
    • 1970-01-01
    • 2021-12-04
    • 2013-12-26
    • 1970-01-01
    相关资源
    最近更新 更多