Чтение данных из NetworkStream, когда сервер закрывается сразу после отправки - PullRequest
0 голосов
/ 19 марта 2012

Я сериализую объекты из Stream с BinaryReader:

class MyClass
{
    public void Read(Stream stream)
    {
        BinaryReader reader = new Reader(stream);

        this.someField = reader.ReadSomething(); // IOException
    }
}

Проблема в одном случае заключается в том, что если я читаю из NetworkStream, сервер закрывает соединение сразу послеотправка данных.Это приводит к IOException («Невозможно прочитать данные из транспортного соединения: существующее соединение было принудительно закрыто удаленным хостом.») даже до того, как я прочитал все содержимоена моей стороне.Как я могу прочитать эти данные?Разве это не буферизовано где-то?

Протокол, который я читаю, TLS , и упомянутая ситуация возникает, если сервер отправляет фатальное предупреждение, и я хочу прочитать это предупреждение, после чего соединение должно быть немедленно закрытос обеих сторон.

Сообщение об исключении:

System.IO.IOException
  Message=Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
  Source=System
  StackTrace:
       at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
       at System.IO.Stream.ReadByte()
       at System.IO.BinaryReader.ReadByte()
       at MyClass.Read(Stream stream)
    [...]
  InnerException: System.Net.Sockets.SocketException
       Message=An existing connection was forcibly closed by the remote host
       Source=System
       ErrorCode=10054
       NativeErrorCode=10054
       StackTrace:
            at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)

class Record
{
    public void Read(Stream stream)
    {
        BinaryReader reader = new BinaryReader(stream);

        byte contentType = reader.ReadByte();
        byte majorVer = reader.ReadByte();
        byte minorVer = reader.ReadByte();
        ushort payloadSize = reader.ReadUInt16();

        if(contentType == 21) // Alert
        {
            Alert alert = new Alert();
            alert.Read(stream);
        }
    }
}

class Alert
{
    public void Read(Stream stream)
    {
        BinaryReader reader = new BinaryReader(stream);

        byte level = reader.ReadByte(); // IOException
        byte desc = reader.ReadByte();
    }
}

Ответы [ 2 ]

2 голосов
/ 19 марта 2012

Это не должно быть проблемой. Если сервер действительно только что отправил все данные и затем упорядоченно закрыл поток, вы должны иметь возможность получить все отправленные им данные. Вы увидите проблему, если соединение было разорвано менее упорядоченным образом или прервано в другом месте, и, возможно, если вы продолжали пытаться читать с него после , оно уже вернуло факт, что оно было закрыто.

Что произойдет, если вы не используете BinaryReader, а просто используете поток и делаете что-то вроде:

// Just log how much data there is...
byte[] buffer = new byte[8 * 1024];
int bytesRead;
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
{
    Console.WriteLine(bytesRead);
}

То, что не должно бросать IOException только из-за изящного закрытия сокета ... оно должно просто выйти из цикла. Если это работает, но ваш существующий код выдает, вам нужно проверить предположения, которые вы делаете в коде чтения (который вы не опубликовали).

0 голосов
/ 20 марта 2012

Это приводит к IOException ("Соединение закрыто ...")

Это, скорее всего, вызвано тем, что ваша сторона закрывает соединение и затем пытается прочитать с него. Удаленное закрытие должно привести только к одному из проявлений условия EOS в API.

Было бы большой ошибкой для API предположить, что входящий TCP FIN означал, что соединение было закрыто: это могло быть отключение, при этом другое направление все еще работало.

...