Помогите устранить петлю в асинхронном приемнике из-за content-length = 0 в ответе HTTP - PullRequest
2 голосов
/ 13 февраля 2010

Некоторые веб-серверы возвращают нулевую длину содержимого в заголовках ответа HTTP. Я хотел бы получить детерминированное и производительное решение для получения всех данных в этой ситуации.

URL-адрес, для которого характерно подобное поведение (дополнительные URL-адреса приведены ниже):

http://www.washingtonpost.com/wp-dyn/content/article/2010/02/12/AR2010021204894.html?hpid=topnews

заголовки:

Cache-control:no-cache
Connection:close
Content-Encoding:gzip
Content-type:text/html
Server:Web Server
Transfer-encoding:chunked

Мое текущее решение не гарантирует получение всех данных из-за константы MaxTries и медленно из-за Thread.Sleep ()

private bool MoreDataIsAvailable()
{
    int avail = _socket.Available;
    if (avail == 0 &&
        _contentLength != null && _contentLength == 0)
    {
        int tries = 0;
        while (avail == 0 && tries < MaxTries)
        {
            Thread.Sleep(5);
            _socket.Poll(1000, SelectMode.SelectRead);
            avail = _socket.Available;
            tries++;
            if (avail > 0)
            {
                Console.WriteLine(_socket.Handle + " avail = " + avail + " received = " + _bytes.Length + " && tries = " + tries);
            }
        }
    }
    return avail > 0;
}

Использование в контексте:

private void ReceiveCallback(object sender, SocketAsyncEventArgs e)
{
    if (ConnectionWasClosed(e) || HadSocketError(e))
    {
        _receiveDone.Set();
        return;
    }

    StoreReceivedBytes(e);

    if (AllBytesReceived())
    {
        _receiveDone.Set();
        return;
    }

    if (MoreDataIsExpected() || MoreDataIsAvailable())
    {
        WaitForBytes(e);
    }
    else
    {
        _receiveDone.Set();
    }
}

Пример вывода:

1436 avail = 3752 received = 1704 && tries = 9
1436 avail = 3752 received = 9208 && tries = 8
1436 avail = 3752 received = 12960 && tries = 9
1436 avail = 3752 received = 20464 && tries = 8
1436 avail = 3752 received = 27968 && tries = 7
1436 avail = 7504 received = 31720 && tries = 1
1436 avail = 3752 received = 39224 && tries = 6

редактирование:

Николай заметил, что ответы с Transfer-encoding: chunked header требуют специальной обработки, но их концы могут быть детерминированно обнаружены.

Однако, за исключением фрагментированных ответов, есть и другие URL-адреса, которые заканчиваются в моем методе всеобъемлющего отслеживания, примеры:

http://www.biomedcentral.com/1471-2105/6/197

заголовки:

Cache-control:private
Connection:close
Content-Type:text/html
P3P:policyref="/w3c/p3p.xml", CP="NOI DSP COR CURa ADMa DEVa TAIa OUR BUS PHY ONL UNI COM NAV INT DEM PRE"
Server:Microsoft-IIS/5.0
X-Powered-By:ASP.NET

http://slampp.abangadek.com/info/

заголовки:

Connection:close
Content-Type:text/html
Server:Apache/2.2.8 (Ubuntu) DAV/2 PHP/5.2.4-2ubuntu5.3 with Suhosin-Patch mod_ruby/1.2.6 Ruby/1.8.6(2007-09-24) mod_ssl/2.2.8 OpenSSL/0.9.8g
X-Cache:MISS from server03.abangadek.com
X-Powered-By:PHP/5.2.4-2ubuntu5.3

http://video.forbes.com/embedvideo/?format=frame&height=515&width=336&mode=render&networklink=1

заголовки:

Connection:close
Content-Language:en-US
Content-Type:text/html;charset=ISO-8859-1
Server:Apache-Coyote/1.1

Я хотел бы знать, что я могу искать в этих ответах, которые, как и заголовок Transfer-encoding для первого URL, дают подсказку для детального определения полного ответа, чтобы можно было избежать вызова моего метода.

1 Ответ

1 голос
/ 14 февраля 2010

По указанному URL вы, похоже, просматриваете HTTP Chunked Transfer Encoding , который позволяет серверу начать передачу ответа до того, как будет определена общая длина, но при этом клиенту достоверно определить конец ответа.

Также см. RFC 2616, раздел 3.6.1 .

...