Клиентская сторона:
recv
возвращает только те данные, которые немедленно доступны или блокируются, пока данные не станут доступны, это вряд ли произойдет с большим файлом или медленной сетью. Весьма вероятно, что recv
будет блокироваться до тех пор, пока не прибудет первый сетевой пакет, и в зависимости от базовой сети, которая может составлять от нескольких сотен байтов до десятков тысяч. Может быть, сообщение вписывается в это, а может и нет.
Установка параметра recv
*1007* на MSG_WAITALL
полезна для более коротких сообщений, поскольку вы либо получите именно то количество байтов, которое вы запросили, либо ошибку. Из-за возможной ошибки вы всегда должны проверять возвращаемое значение.
Повторить: всегда проверяйте возвращаемое значение.
Возвращаемое значение
recv
является либо отрицательным при отказе сокета, либо 0 при отключении сокета, либо количеством прочитанных байтов. За дополнительной информацией обращайтесь к документации winsock для recv
.
Итак ...
recv(Connection, (char*)&msg_size, sizeof(unsigned long), NULL);
и
recv (Connection, (char *) & msgl_size, sizeof (unsigned long), NULL);
не проверять возвращаемое значение. Возможно, произошел сбой сокета, или вызов recv
мог бы вернуть меньше, чем было запрошено, и остальная часть программы будет работать на мусоре.
Это подходящее место для использования MSG_WAITALL
, но возможно, что с розеткой все в порядке, и вы были прерваны сигналом. Не уверен, что это может произойти в Windows, но в Linux. Осторожно.
if (recv(Connection, (char*)&msg_size, sizeof(unsigned long), MSG_WAITALL) != sizeof(unsigned long) &&
recv(Connection, (char*)&msgl_size, sizeof(unsigned long), NULL) != sizeof(unsigned long)(
{
// log error
// exit function, loop, or whatever.
}
Далее
do {
res = recv(Connection, reinterpret_cast<char*>(msgl), msgl_size, NULL);
} while (msgl_size != res);
будет повторяться до тех пор, пока один recv
не вернет точно правильную сумму за один вызов. Маловероятно, но если это произойдет, это должно произойти при первом чтении, потому что код записывает поверх предыдущего чтения каждый раз.
Скажем, только половина сообщения читается из сокета с первой попытки. Поскольку это не полное сообщение, цикл входит и пытается прочитать снова, перезаписывая первую половину сообщения второй половиной и, возможно, достаточно байтов из последующего сообщения, чтобы удовлетворить запрошенное количество байтов. Эта амальгама из двух сообщений не расшифровывается.
Для полезной нагрузки потенциально большого размера зацикливайтесь, пока программа не получит все это.
char * bufp = reinterpret_cast<char*>(msgl);
int msg_remaining = msgl_size;
while (msg_remaining )
{
res = recv(Connection, bufp, msg_remaining, NULL);
if (res <= 0)
{
// log error
// exit function, loop, or whatever.
}
msg_remaining -= res; // reduce message remaining
bufp += res; // move next insert point in msgl
}
Возможны проблемы с декомпрессией. Я не знаю достаточно об этом, чтобы иметь возможность ответить. Я предлагаю удалить его и отправить легко отлаживаемый текст, пока не будут решены все проблемы с сетью.
Серверная сторона:
Как и recv
, send
отправляет, что может. Возможно, вам придется зациклить отправку, чтобы убедиться, что вы не переполнили сокет сообщением, слишком большим для сокета, чтобы его можно было съесть за один раз. И снова, как recv
, s send
может выйти из строя. Всегда проверяйте возвращаемое значение, чтобы увидеть, что на самом деле произошло. Обратитесь к документации для send
для получения дополнительной информации.