Итак, моя проблема в том, что у меня есть файл, который я хотел бы опубликовать boost:asio
http сервер. Клиентское приложение находится на C #. Поэтому я стараюсь делать следующее, основываясь на множестве постов здесь и даже на собственном сайте Microsoft.
string fileToSendServer = "Contains lots of data that needs to be written to file";
byte[] byteArray = UTF8Encoding.UTF8.GetBytes(fileToSendServer);
// Create a request using a URL that can receive a post.
request = WebRequest.Create(destination);
// Set the Method property of the request to POST.
request.Method = "POST";
// Set the ContentType property of the WebRequest.
request.ContentType = "application/octet-stream";
// Set the ContentLength property of the WebRequest.
request.ContentLength = byteArray.Length;
// Get the request stream.
using (dataStream = request.GetRequestStream())
{
// Write the data to the request stream.
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Flush();
// Close the Stream object.
dataStream.Close();
}
Клиент проходит весь путь до GetRequestStream()
и это, кажется, отправляет заголовки ожидающему серверу. Сервер обрабатывает заголовки и никогда не получает байты от Write()
,
Я пытался использовать Fiddler2 для просмотра пакетов, но моя ИТ-служба заблокировала мою машину, поэтому я не могу запустить Fiddler.
Когда я шагаю по коду для клиента, все строки кода выполняются. И когда я перехожу на сервер, в потоке обнаруживаются только заголовки.
Данные, которые должны быть отправлены, генерируются клиентом, а не файлом, пока они не будут записаны в файл на стороне сервера. Сервер похож на один из boost::asio
http примеры серверов. Так что я не знаю, клиент это или сервер. Я прошел через код для разбора входного ввода, и данные никогда не были получены. Поэтому я посмотрел на соединение и, насколько я могу судить, не блокирует входящие данные.
РЕДАКТИРОВАТЬ:
Хорошо, основываясь на ответах (включая мои собственные), я добился значительного прогресса. Половина проблемы заключалась в том, что c # не читал все до отправки. Теперь клиент C # читает и отправляет данные. Клиент сообщает, что команда send отправила все байты. Но boost: asio http server 3 все еще не получает все данные. Проблема в том, что я использую пример http-сервера и модуль запроса кажется, не захватывает все данные. Он читает по одному байту за раз и, кажется, умирает при 0x1f48 байтов содержимого.
template <typename InputIterator>
boost::tuple<boost::tribool, InputIterator> parse(request& req,
InputIterator begin, InputIterator end)
{
while (begin != end)
{
boost::tribool result = consume(req, *begin++);
if (result || !result)
{
return boost::make_tuple(result, begin);
}
}
boost::tribool result = boost::indeterminate;
if(state_ == getting_content) {
result = boost::indeterminate;
}
return boost::make_tuple(result, begin);
}
Начало == конец, когда только 8008 байт были прочитаны из запроса.
(Этот ответ основан на новой информации, которую вы предоставили на текущий принятый ответ)
Все Stream
классы, которые реализуют Read
требуется только прочитать вплоть до количество байтов, переданных для подсчета. Вот и вся причина, по которой он возвращает int
,
Также из-за Read
не берет long
по своим параметрам вы все равно будете пропускать данные, если возвращаемый контент больше чем Int32.MaxLength
,
Правильный способ сделать это — прочитать в меньший буфер и позволить этому буферу скопировать в ваш больший массив.
byte[] data = new byte[response.ContentLength];
byte[] buffer = new byte[4 << 10]; //4k buffer, you can tweak it if you need to
long offset = 0;
int read;
do
{
read = dataStream.Read(buffer, 0, buffer.Length);
Array.Copy(buffer, 0, data, offset, read);
offset += read;
} while (read > 0);
Я не знаю что List<byte> content
для, если вы просто собираетесь двигаться data
в к content
знать, что у вас могут возникнуть некоторые проблемы, если response.ContentLength
больше чем Int32.MaxLength
потому что нет членов, чтобы вытащить с помощью индекса или получить длину через long
вместо int
,
Видимо response.GetResponseStream()
возвращает Stream
это не будет Read()
весь ответ. Чтобы решить эту проблему, мне нужно было построить следующее в ответе:
byte[] data = new byte[response.ContentLength];
int offset = 0;
while (offset < response.ContentLength)
{
offset += dataStream.Read(data, offset, (int)(response.ContentLength - offset));
}
List<byte> content = new List<byte>(2 * (int)response.ContentLength);
Затем я смог написать через второй поток, который, наконец, получил весь отправленный контент. Каждый раз, когда я проверял вывод файла перед этим изменением, файл содержал именно то, что было в содержании. Таким образом, похоже, что вся проблема была основана на первоначальном ответе, а не на «чтении» всех отправленных данных.
РЕДАКТИРОВАТЬ:
Кроме того, данные, поступающие на сервер, не были полными. boost:asio
Пример кода http имел проблемы с захватом всех данных контента. Я бы получил только часть входящего контента или данных файла. Казалось, что каждый раз останавливается на 8008 байт. Я обнаружил, что функция разбора была неправильной. Поэтому я изменил это так:
template <typename InputIterator>
boost::tuple<boost::tribool, InputIterator> parse(request& req,
InputIterator begin, InputIterator end)
{
//may have to handle multipart here.
while (begin != end)
{
boost::tribool result = consume(req, *begin++);
if (result || !result)
{
return boost::make_tuple(result, begin);
}
}
boost::tribool result = boost::indeterminate;
if(state_ == getting_content) {
if(req.content.length() < content_length_) {
result = boost::indeterminate;
} else {
result = true;//boost::indeterminate;
}
}
return boost::make_tuple(result, begin);
}
Самая большая часть должна была сделать проверку на content
длина и возврат indeterminate
для этой функции. И затем убедитесь, что connection
был код для read_some
больше, что есть в примере кода.