Я пытаюсь загрузить файл с моего сайта с помощью winsock. я столкнулся с бесчисленными проблемами и теперь смог загрузить файл, но его испортил.
Он не работает с любым расширением файла. Текст и картинки в конечном итоге повреждены, аудиофайлы тоже. С бинарными файлами я вижу эту ошибку при выполнении "слишком большой программы, чтобы вписаться в память".
Сначала я посылаю() запрос главы на сервер, чтобы узнать размер содержимого (размер загружаемого файла), затем я отправляю запрос Get и я возвращаю в буфер. После выполнения recv я напишу файл.
Я попытался написать простой пример кода здесь, я пробовал различные петлевые подходы, но в конце у меня все еще есть поврежденный файл, записанный на диск. размер тот же (файл 50 КБ на сервере, файл 50 КБ, загруженный и записанный на диск). Спасибо вам всем.
headrequest = "HEAD " + "/folder/file.asd" + " HTTP/1.1\r\nHost: " + "url.com" + "\r\n\r\n";
getrequest = "GET " + "/folder/file.asd" + " HTTP/1.1\r\nHost: " + "url.com" + "\r\n\r\n";
send(socket, headrequest, sizeof(headrequest), 0);
recv(socket, reply_buf_headrequest, sizeof(reply_buf_headrequest), 0);
//two functions to get the header end and "Content-Lenght" data from header
send(socket, getrequest, sizeof(getrequest), 0);
while(1)
{
recv(socket, recvbuff, sizeof(recvbuff), 0);
if (recv(socket, recvbuff, sizeof(recvbuff), 0) == 0)
break;
}
out.write(recvbuff, content_lenght); // also tried --> out.write(recvbuff + header_end, content_lenght) //same errors.
out.close();
Я прикручиваю буфер/позицию, чтобы начать чтение/запись или что-то в этом роде. Я думал, что использование recvbuff + header_end будет работать, так как он начнет чтение с конца заголовка, чтобы получить файл. Это смущает. Надеюсь, одна любезная душа поможет мне разобраться, как справиться с этой ситуацией и правильно записать байты файлов. :)
Редактировать:
Я думал, что я переписываю данные. черт. content_length поступает из предыдущего запроса HEAD, функция считывает полученные данные и находит значение "Content-Length", которое является размером в байтах /folder/file.asd. я не смог получить его в запросе Get, поэтому я сделал это так: размер файла, который он получает, верен.
так,
while(1)
{
if (recv(socket, recvbuff, sizeof(recvbuff), 0) == 0)
break;
}
out.write(recvbuff, content_lenght);
out.close();
out.write следует после цикла или внутри цикла while (1)?
Спасибо за быстрый ответ. :)
Я пропустил часть проверки ошибок, чтобы код примера был коротким, извините. голова и запрос на получение - это символы, я тоже пытался использовать строки и не использовал для этого sizeof(). я не могу получить доступ к реальному коду до завтра, поэтому я пытаюсь исправить его дома, используя похожий фрагмент. Возможно, есть некоторые опечатки.
Редактировать 2: как тест с небольшим exe, который только порождает ящик сообщений im, используя буфер больше, чем файл, и это:
ofstream out("test.exe", ios::binary);
и используя этот цикл сейчас:
int res; // return code to monitor transfer
do {
res = recv(socket, recvbuff, sizeof(recvbuff), 0); // look at return code
if (res > 0) // if bytes received
out.write(recvbuff, res ); // write them
} while (res>0); // loop as long as we receive something
if (res==SOCKET_ERROR)
cerr << "Error: " << WSAGetLastError() << endl;
все еще имея ошибку "program too large to fit in memory" при исполнении.
Это нормально! Ваш код действительно не заботится о содержимом, который вы получаете!
Смотрите мои комментарии:
while(1) // Your original (indented) code commented:
{
recv(socket, recvbuff, sizeof(recvbuff), 0); // You read data in buffer
if (recv(socket, recvbuff, sizeof(recvbuff), 0) == 0) // you read again, overwriting data you've received !!
break;
}
out.write(recvbuff, content_lenght); // You only write the last thing you've received.
// Where does the lengthe come from ? Maybe you have buffer overflow as well.
Перепишите свой цикл следующим образом:
int res; // return code to monitor transfer
do {
res = recv(socket, recvbuff, sizeof(recvbuff), 0); // look at return code
if (res > 0) // if bytes received
out.write(recvbuff, res ); // write them
} while (res>0); // loop as long as we receive something
if (res==SOCKET_ERROR)
cerr << "Error: " << WSAGetLastError() << endl;
Преимущество состоит в том, что вам не нужно заботиться об общем размере, так как вы пишете каждый небольшой кусок, который вы получаете.
Редактировать:
После нашего обмена комментариями, здесь есть дополнительная информация. Как заметил кто-то, HTTP-протокол несколько сложнее управлять. См. Здесь, в главе 6, для получения дополнительной информации о формате ответа и заголовке, который вы должны пропустить.
Здесь некоторое обновленное доказательство концепции, чтобы пропустить заголовок:
ofstream out;
out.open(filename, ios::binary);
bool header_skipped=false; // was header skiped (do it only once !!)
int res; // return code to monitor transfer
do {
res = recv(mysocket, recvbuff, sizeof(recvbuff), 0); // look at return code
if (res > 0) // if bytes received
{
size_t data_offset = 0; // normally take data from begin of butter
if (!header_skipped) { // if header was not skipped, look for its end
char *eoh = "\r\n\r\n";
auto it = search (recvbuff, recvbuff + res, eoh, eoh + 4);
if (it != recvbuff + res) { // if header end found:
data_offset = it - recvbuff + 4; // skip it
header_skipped = true; // and then do not care any longer
} // because data can also containt \r\n\r\n
}
out.write(recvbuff + data_offset, res - data_offset); // write, ignoring before the offset
}
} while (res > 0); // loop as long as we receive something
if (res == SOCKET_ERROR) cerr << "Error: " << WSAGetLastError() << endl;
out.close();
Внимание! Как сказано, это доказательство концепции. Это, вероятно, будет работать. Однако имейте в виду, что вы не можете быть уверены, как данные будут перегруппированы со стороны приемника. Вполне возможно, что конец заголовка разделяется между двумя последовательными чтениями (например, \r
как последний байт одного recv() и \n\r\n
качестве первых байтов следующего recv()
). В таком случае этот простой код не найдет его. Так что это еще не код качества продукции. До вас, чтобы улучшить