Максимальное значение size_t при send () в C - PullRequest
0 голосов
/ 07 мая 2019

Я пишу tcp сервер на C, но у меня возникают проблемы при отправке. Я читаю локальный файл и отправляю данные обратно клиенту, когда файл маленький, у меня нет проблем, но когда он становится больше, возникает странная ситуация:

tcp сервера:

 // create socket, bind, listen accept

// read file
fseek(fptr, 0, SEEK_SET);
// malloc for the sending buffer
ssize_t read = fread(sbuf, 1, file_size, fptr);

while(to_send>0) {
  sent = send(socket, sbuf, buf_size, 0);
  sbuf += sent;
  to_send -= sent;
}

При отправке огромных файлов становится равным максимальному значению size_t, я думаю, что у меня переполнение буфера. Как я могу предотвратить это? Как лучше читать файл и отправлять его обратно?

Ответы [ 2 ]

3 голосов
/ 07 мая 2019

Проблема в том, что вы отправляете buf_size байт каждый раз, даже если их не так много.

Например, притвориться buf_size равно 8, а вы отправляете 10 байтов (поэтому изначально to_send также равно 10). Первый send отправляет 8 байтов, поэтому вам нужно отправить еще 2. Во второй раз вы также отправляете 8 байтов (что, вероятно, читает за пределами). Тогда to_send будет равен -6, что равно SIZE_MAX - 5.

Простое исправление - отправить to_send, если оно меньше:

sent = send(socket, sbuf, to_send < buf_size ? to_send : buf_size, 0);

Кроме того, send возвращает -1, если это не удалось. Это то же самое, что и SIZE_MAX, когда оно назначено для size_t. Чтобы исправить это, вам понадобится некоторая обработка ошибок.

0 голосов
/ 07 мая 2019

При отправке огромных файлов становится равным максимальному значению size_t, я думаю, что у меня переполнение буфера.

Поскольку sent получает свое значение в качестве возвращаемого значения send(), а send() возвращает ssize_t, что является типом со знаком, который вряд ли будет шире, чем size_t. Фактически очевидно, что в действительности send() указывает на ошибку, возвращая -1.В этом случае также будет установлено значение errno, указывающее на ошибку.Он не может вернуть максимальное значение size_t в любой системе, в которой у меня когда-либо были руки.

Как я могу предотвратить это?

Во-первыхпрежде чем беспокоиться о предотвращении этого, вы должны обязательно обнаружить его по

  1. , объявив sent как ssize_t в соответствии с возвращаемым значениемтип send(), а не size_t и
  2. , проверяющий значение, возвращенное в sent для таких условий ошибки.

Во-вторых, если вы действительно имеете дело с файламидольше, чем может быть представлено ssize_t (намного меньше size_t), тогда плохая идея загрузить все это в память перед отправкой любого из них.Вместо этого загрузите его в (гораздо) меньшие блоки и отправляйте данные по одному такому блоку за раз.Это не только приведет к снижению воспринимаемой задержки, но и позволит избежать любого риска, связанного с приближением к пределам используемых типов данных.

Кроме того, при этом соблюдайте осторожность, чтобы сделать это правильно.Вы преуспели в том, чтобы обернуть свой вызов send() в цикл для учета коротких записей, но, как описывает @Artyer в своем ответе, вы не совсем понимаете это правильно, потому что не уменьшаете количество байтов, которые вы пытаетесь отправитьна второй и последующие вызовы.

Как лучше прочитать файл и отправить его обратно?

Как указано выше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...