服务器客户端通过原始数据错误C ++发送接收结构

时间:2018-03-30 17:01:46

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

我正在通过TCP / IP为结构(在我的情况下" frame")执行发送和接收功能。但功能似乎没有成功,我找不到我的错误。我被要求将所有数据存储在一个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;

}

有谁能告诉我我的错误在我的功能中是什么?

1 个答案:

答案 0 :(得分:0)

您没有检查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;
}