У меня есть HttpListener
, который прослушивает любые запросы файлов на локальном хосте (то есть 192.168.0.10/Foobar.ext) на указанном порту (в данном случае, в частности, это поток HLS, использующий заголовочные файлы .m3u8 и .ts видеофайлы. Но система должна работать для любого типа файла).
IAsyncResult result = listener.BeginGetContext(new AsyncCallback(HttpRequestListenerCallback), listener);
result.AsyncWaitHandle.WaitOne(1);
Когда запрос сделан, обратный вызов создает HttpListenerContext
для запрошенного файла (и только этого файла) и извлекает имя файла следующим образом:
HttpListenerContext context = listener.EndGetContext(result);
string fileName = context.Request.Url.AbsolutePath.Substring(1);
контекст добавляется в словарь с именем httpContexts
и связывается с int commandSequenceNumber
для отслеживания запросов.
Если имя файла действительно, запросы отправляются на сервер для загрузки файла. Файл загружается и помещается в байтовый массив с именем totalBufferdata
. до здесь все работает отлично.
Теперь я хочу записать байтовые данные запрошенного (видео) файла обратно в ответ (HttpListenerContext.Response
) контекста, в котором был запрошен файл
Для этого я использую следующий фрагмент кода (это происходит после , когда файл был полностью загружен):
HttpListenerResponse response = httpContexts[commandSequenceNumber].Response; //Get the appropriate context from the dictionary
response.ContentLength64 = totalBufferdata.Count;//set the length response body
Stream responseStream = response.OutputStream; //The stream to which the repsonse needs to be written
try
{
currentContext.Response.OutputStream.Write(dataNoResponseHeader, 0, dataNoResponseHeader.Length);
}
catch (IOException e)
{
Debug.LogError("Exception in writing to response::" + e);
Debug.LogError("innerException:: " + e.InnerException);
}
currentContext.Close();//close the request and response stream
Это отправляет ответ обратно в контексте запроса (т. Е. 192.168.0.10/Foobar.ext, через тот же порт).
Теперь это работает нормально, , пока есть быстрое и надежное подключение к Интернету . Когда подключение к Интернету медленное или несовместимое, я начинаю получать исключение:
System.IO.IOException: Unable to write data to the transport connection: The socket has been shut down. ---> System.Net.Sockets.SocketException: The socket has been shut down
С внутренним исключением:
System.Net.Sockets.SocketException (0x80004005): The socket has been shut down
Я посмотрел, что HResult из 0x80004005
подтвердил до на msdn , но это просто "E_FAIL Unspecified fail", так что не повезло.
Мне не удалось выяснить, почему это вызвало бы ожидание закрытия сокета (и почему это происходит в части localhost , но только при плохом соединении ). Я проверяю все необходимые данные в totalBufferData
, поэтому низкая скорость интернета не должна влиять на это, так как все данные уже загружены, прежде чем я запишу их в ответ. Я убедился, что не закрываю контекст преждевременно нигде в моем коде.
До сих пор мне не удавалось найти способ добраться до основного сокета HttpListener
. Я также попытался привести response.OutputStream
к NetworkStream
и получить сокет от NetworkStream, но это преобразование недопустимо (Что смутило меня, поскольку они оба являются потоками ввода-вывода?). Думая, что это может быть закрытой проблемой, я тоже попробовал
using(Stream testStream = response.OutputStream)
{
testStream.Write(totalBufferdata.ToArray(), 0, totalBufferdata.Count);
}
Мне кажется, что эта проблема связана с таймаутом где-то . Но Слушатель не достигает времени ожидания по умолчанию. В соответствии с для MSDN все тайм-ауты по умолчанию должны составлять 2 минуты. К чему я нигде не подхожу. И я думаю, что исключение, возвращаемое в случае тайм-аута, должно быть ObjectDisposedException Write(Byte[], Int32, Int32) was called after the stream was closed.
, так как я полагаю, что тайм-аут избавит от соединения, а не прервет его? Это недоразумение?
Запросы и ответы выполняются в отдельных потоках. Но запрос, который выполняется, пока ответ еще находится в процессе, ставится в очередь и ожидает завершения ответа, прежде чем он начнет новый ответ.
Есть ли способ получить и отладить базовый сокет, чтобы выяснить, почему он закрывается / падает? Или, может быть, альтернативный подход к запросу файла через localhost и ответ на него, который не использует HttpListener
?
Некоторая дополнительная информация: это для приложения Unity (Unity 2019.1), использующего версию среды выполнения сценариев .Net 4.x эквивалентно, с уровнем совместимости API .Net 4.x и сценарием IL2CPP. Но ни один из классов, обрабатывающих запрос или ответ, не наследуется от monobevahiour (что даже невозможно для потоков в единице). Сборка для Android.
Щедрость закончилась, но я открою новую для каждого, кто имеет какую-либо ценную информацию!