Инициализировать массив C для пользовательского символа - PullRequest
0 голосов
/ 16 декабря 2018

Я построил сервер Winsock2.Часть этой программы имеет функцию, которая получает данные от клиентов.Первоначально созданная мной функция приема смотрела на входящие данные и определяла, есть ли какие-либо дополнительные данные для чтения, прежде чем recv() сможет извлечь данные из буфера.Это отлично работало в начале проекта, но сейчас я работаю над повышением производительности.

Вот часть кода, которую я написал, чтобы исключить использование peek:

    unsigned char recv_buffer[4096];
    unsigned char *pComplete_buffer = malloc(sizeof(recv_buffer) * sizeof(unsigned char*));
    int offset = 0;
    int i = 0;

    ...

    for (i; i <= sizeof(recv_buffer); i++) {
        if (recv_buffer[i] == NULL) {
            break;
        }
        pComplete_buffer[offset] = recv_buffer[i];
        offset++;
    }

    ...

Этот код будет отлично работать, но проблема в том, что NULL == 0.Если клиент отправит 0, этот цикл преждевременно прервется.Я думал, что был бы умен и оставил бы данные неинициализированными до 0xcc и использовал бы это, чтобы определить конец recv_buffer, но кажется, что клиенты иногда также отправляют это как часть своих данных.

Вопрос:

Есть ли символ, который я могу инициализировать recv_buffer, чтобы надежно сломать его?

Если нет, есть ли другой способ, которым я могу исключить использование peek?

Ответы [ 2 ]

0 голосов
/ 18 декабря 2018

Правильное решение - отслеживать, сколько байтов вы храните в recv_buffer для начала.sizeof() дает вам ОБЩИЙ ВОЗМОЖНЫЙ размер буфера, но не говорит, КАК МНОГИЕ байты на самом деле содержат действительные данные.

recv() говорит вам, сколько байтов он возвращает вам.Когда вы recv() данных в recv_buffer, используйте это возвращаемое значение для увеличения переменной, которую вы определили, чтобы указать количество действительных байтов в recv_buffer.

Например:

unsigned char recv_buffer[4096];
int num_read, recv_buffer_size = 0;

const int max_cbuffer_size = sizeof(recv_buffer) * sizeof(unsigned char*);
unsigned char *pComplete_buffer = malloc(max_cbuffer_size);

...

num_read = recv(..., recv_buffer, sizeof(recv_buffer), ...);
if (num_read <= 0) {
    // error handling...
    return;
}
recv_buffer_size = num_read;

...

int available = max_cbuffer_size - offset;
int num_to_copy = min(recv_buffer_size, available);

memcpy(pComplete_buffer + offset, recv_buffer, num_to_copy);
offset += num_to_copy;
memmove(recv_buffer, recv_buffer + num_to_copy, recv_buffer_size - num_to_copy);
recv_buffer_size -= num_to_copy;

...
0 голосов
/ 16 декабря 2018

Есть ли символ, который я могу инициализировать recv_buffer и надёжно сломать?

Нет.Если другая сторона может отправить какого-либо персонажа в любое время, вам придется изучить его.

Если вы знаете, что отправитель никогда не отправит две NUL с подряд (\0\0), вы можете проверить это.Но когда-нибудь отправитель решит это сделать.

Если вы сможете изменить структуру сообщения, я сначала отправлю длину сообщения (в байтах, по сети или по типу int в зависимости от вашего протокола).,Затем, после анализа этой длины, получатель будет точно знать, как долго продолжать чтение.Также, если вы используете select, он будет блокироваться до тех пор, пока не будет что прочитать, или сокет не закроется (в основном - читайте документы).

...