Я реализую один сервер с новым разработанным протоколом. В соответствии с протоколом клиент отправляет заголовок, за которым следуют данные. Заголовок содержит метаинформацию, включая размер данных.recv() для большого количества данных не работает
Мы предоставляем образец клиента, но клиентская программа также может быть написана третьим лицом. Таким образом, мы не можем полностью полагаться на размер данных поле, указанное в заголовке.
Теперь у меня возникла одна проблема с системным вызовом recv()
.
#define SOCKET_CHUNK_SIZE 4096
void * value;
1 value = (void *) malloc(hdr.size);
2 total_bytes_read = 0;
3 while(total_bytes_read < hdr.size) {
4 n = recv(newsockfd, value + total_bytes_read, SOCKET_CHUNK_SIZE, 0);
5
6 //fprintf(stderr, " %ld + %d = %ld\n", total_bytes_read, n, total_bytes_read + n);
7
8 total_bytes_read += n;
9
10 if(n == 0 || n < SOCKET_CHUNK_SIZE)
11 break;
12 if(n < 0)
13 send_error_response(newsockfd);
14 }
15
16 fprintf(stderr, "%ld", total_bytes_read);
Это прекрасно работает для небольшого объема данных (например, 9420 байт), но не подходит для большей суммы.
Наблюдение:
Пусть клиент посылает некоторое большое количество данных, как 604697 байт (hdr.size):
recv()
может читать только 65280 байт. т.е. fprintf на линии № 16 печатает 65280. (я проверил SSIZE_MAX на моей машине, и это 2147483647, так что это гораздо больше, чем SOCKET_CHUNK_SIZE)Я попытался с помощью MSG_DONTWAIT флаг
recv()
вызова, но результат тот же.Я попытался использовать
read()
системный вызов вместоrecv()
, результат такой же.Когда я раскомментирую строку # 6, она отлично работает !! (Но эта строка (и строка № 16) предназначена только для цели отладки. Я не могу сохранить ее в окончательной версии).
Если я использую флаг MSG_WAITALL в
recv()
, он работает, но блокирует при чтении последнего фрагмента как последний кусок размер меньше, чем SOCKET_CHUNK_SIZE (604697 = 147 * 4096 + 2585). Таким образом, я не могу использовать этот флаг, если только не зависит от размера, предоставленного в заголовке от клиента и изменяющегося вrecv()
.
Данные, предоставленные клиентом, также могут быть двоичными, поэтому мы не можем указывать какой-либо показатель как конец данных.
Любой, у кого есть идеи/решения, приветствуется. Как я уже упоминал, у нас есть решение - полагаться на заголовок клиента, но я предпочту его, только когда не найду других способов.
Ravi
'n
Rohan
Вы не должны увеличивать 'total_bytes_read' до тех пор, пока не узнаете, что' n> 0'. – EJP
@EJP. Если 'n <0', он отправит ошибку и не примет данные – Ravi