Розетки получают зависания - PullRequest
1 голос
/ 21 июля 2011

Я пытаюсь загрузить, найти страницу bing и спросить, используя сокеты, я решил использовать сокеты вместо веб-клиента.

Сокет . Receive (); зависаетпосле нескольких петель в случае bing, Yahoo, Google, но работает на аск.для гугл петли получат 4 - 5 раз, потом заморозят при звонке.

Не могу разобраться почему?

public string Get(string url)
{
    Uri requestedUri = new Uri(url);
    string fulladdress = requestedUri.Host;
    IPHostEntry entry = Dns.GetHostEntry(fulladdress);
    StringBuilder sb = new StringBuilder();

    try
    {
        using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP))
        {
            socket.Connect(entry.AddressList[0], 80);

            NetworkStream ns = new NetworkStream(socket);

            string part_request = string.Empty;
            string build_request = string.Empty;
            if (jar.Count != 0)
            {
                part_request = "GET {0} HTTP/1.1\r\nHost: {1} \r\nUser-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Language: en-us,en;q=0.5\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\nCookie: {2}\r\nConnection: keep-alive\r\n\r\n";
                build_request = string.Format(part_request, requestedUri.PathAndQuery, requestedUri.Host, GetCookies(requestedUri));
            }
            else
            {
                part_request = "GET {0} HTTP/1.1\r\nHost: {1} \r\nUser-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Language: en-us,en;q=0.5\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\nConnection: keep-alive\r\n\r\n";
                build_request = string.Format(part_request, requestedUri.PathAndQuery, requestedUri.Host);
            }

            byte[] data = Encoding.UTF8.GetBytes(build_request);
            socket.Send(data, data.Length, 0);

            byte[] bytesReceived = new byte[102400];
            int bytes = 0;

            do
            {
                bytes = socket.Receive(bytesReceived, bytesReceived.Length, 0);
                sb.Append(Encoding.ASCII.GetString(bytesReceived, 0, bytes));
            }
            while (bytes > 0);

            List<String> CookieHeaders = new List<string>();
            foreach (string header in sb.ToString().Split("\n\r".ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
            {
                if (header.StartsWith("Set-Cookie"))
                {
                    CookieHeaders.Add(header.Replace("Set-Cookie: ", ""));
                }
            }

            this.AddCookies(CookieHeaders, requestedUri);

            socket.Close();
        }
    }
    catch (Exception ex)
    {
        string errorMessage = ex.Message;
    }

    return sb.ToString();
}

CookieContainer jar = new CookieContainer();

public string GetCookies(Uri _uri)
{
    StringBuilder sb = new StringBuilder();
    CookieCollection collection = jar.GetCookies(_uri);

    if (collection.Count != 0)
    {
        foreach (Cookie item in collection)
        {
            sb.Append(item.Name + "=" + item.Value + ";");
        }
    }
    return sb.ToString();
}

Ответы [ 3 ]

8 голосов
/ 21 июля 2011

Это потому, что вы достигли конца содержимого и все еще запрашиваете больше ...

do
{
   bytes = socket.Receive(bytesReceived, bytesReceived.Length, 0);
   sb.Append(Encoding.ASCII.GetString(bytesReceived, 0, bytes));
}
while (bytes > 0);

Это предполагает, что до тех пор, пока последний запрос вернул больше 0 байтов, будет больше доступныхкогда на самом деле, когда сетевой поток достигает конца, есть вероятность, что вы заполняете часть своего буфера в последнем цикле.(например, байты> 0, но больше ничего не получается) ... поэтому сервер закрывает соединение.

вместо этого попробуйте что-то подобное ...

do
{
   bytes = socket.Receive(bytesReceived, bytesReceived.Length, 0);
   sb.Append(Encoding.ASCII.GetString(bytesReceived, 0, bytes));
}
while (bytes == bytesReceived.Length);

Некоторые серверы (возможно, спроситеодно из них) очевидно, что не происходит автоматическое закрытие соединения, как можно было бы ожидать, потому что это не всегда происходит сбой.

::: EDIT :::

Мой тестовый образец:

Загрузите Visual Studio, создайте новое консольное приложение, затем вставьте следующее в сгенерированный класс программы (вместо всего существующего кода):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string test = Get("http://www.google.co.uk/search?q=test&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:en-GB:official&client=firefox-a");
            Console.Read();
        }

        public static string Get(string url)
        {
            Uri requestedUri = new Uri(url);
            string fulladdress = requestedUri.Host;
            IPHostEntry entry = Dns.GetHostEntry(fulladdress);
            StringBuilder sb = new StringBuilder();

            try
            {
                using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP))
                {
                    socket.Connect(entry.AddressList[0], 80);

                    NetworkStream ns = new NetworkStream(socket);

                    string part_request = string.Empty;
                    string build_request = string.Empty;
                    if (jar.Count != 0)
                    {
                        part_request = "GET {0} HTTP/1.1\r\nHost: {1} \r\nUser-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Language: en-us,en;q=0.5\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\nCookie: {2}\r\nConnection: keep-alive\r\n\r\n";
                        build_request = string.Format(part_request, requestedUri.PathAndQuery, requestedUri.Host, GetCookies(requestedUri));
                    }
                    else
                    {
                        part_request = "GET {0} HTTP/1.1\r\nHost: {1} \r\nUser-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Language: en-us,en;q=0.5\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\nConnection: keep-alive\r\n\r\n";
                        build_request = string.Format(part_request, requestedUri.PathAndQuery, requestedUri.Host);
                    }

                    byte[] data = Encoding.UTF8.GetBytes(build_request);
                    socket.Send(data, data.Length, 0);

                    byte[] bytesReceived = new byte[4096];
                    int bytes = 0;
                    string currentBatch = "";

                    do
                    {
                        bytes = socket.Receive(bytesReceived);
                        currentBatch = Encoding.ASCII.GetString(bytesReceived, 0, bytes);
                        Console.Write(currentBatch);
                        sb.Append(currentBatch);
                    }
                    while (bytes == bytesReceived.Length);

                    List<String> CookieHeaders = new List<string>();
                    foreach (string header in sb.ToString().Split("\n\r".ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
                    {
                        if (header.StartsWith("Set-Cookie"))
                        {
                            CookieHeaders.Add(header.Replace("Set-Cookie: ", ""));
                        }
                    }

                    //this.AddCookies(CookieHeaders, requestedUri);

                    socket.Close();
                }
            }
            catch (Exception ex)
            {
                string errorMessage = ex.Message;
            }

            return sb.ToString();
        }

        static CookieContainer jar = new CookieContainer();

        public static string GetCookies(Uri _uri)
        {
            StringBuilder sb = new StringBuilder();
            CookieCollection collection = jar.GetCookies(_uri);

            if (collection.Count != 0)
            {
                foreach (Cookie item in collection)
                {
                    sb.Append(item.Name + "=" + item.Value + ";");
                }
            }
            return sb.ToString();
        }
        }
    }

Я уменьшил буфер, чтобы он был заполнен больше, чемоднажды ... с моей стороны все в порядке. Это сообщение сопровождается типичными работами на моем компьютере:)

0 голосов
/ 14 марта 2017

Тестирование количества полученных байтов должно работать большую часть времени, но что произойдет, если последний кусок данных соответствует длине буфера?

byte[] requestBuffer = new byte[100];
int bytesRead;
do
{
    bytesRead = socket.Receive(requestBuffer);
    //do something
}
while (bytes == bytesReceived.Length);

Я предлагаю использовать свойство Available, чтобы программа перестала читать, когда ничего более недоступно

byte[] requestBuffer = new byte[100];
int bytesRead;
while (socket.Available > 0)    
{
    bytesRead = socket.Receive(requestBuffer);
    //do something
}
0 голосов
/ 21 июля 2011

Вы читаете больше контента из потока, чем вам было дано.

  1. Итак, вы открываете соединение с Google и запрашиваете домашнюю страницу.
  2. Google предоставит вам свою домашнюю страницу, скажем, размером 10 КБ.
  3. Вы выделяете буфер размером 102400 байт (он же размером 100 КБ) - в 10 раз больше, чем вам нужно.

Теперь проблема возникает.

  1. Вы читали домашнюю страницу, по несколько байт за раз, и теперь вы достигли отметки 10 КБ. Google накормил вас всей домашней страницей, НО вы продолжаете пытаться читать, пытаясь запросить больше данных! Что происходит, теперь вы просто ждете больше данных, больше данных, которые не приходят! Вы просто ждете вечно, пока не истечет время ожидания. Но поскольку вы указали (в своем коде) получение до тех пор, пока не прочитали 100 КБ, а получили только 10 КБ, вы никогда не доберетесь и, кажется, зависаете в этом цикле!

Решение?

Проверьте, получили ли вы какие-либо байты.

bytes = socket.Receive(...);
if (bytes == 0)
{
    // no more data, exit loop. you can `break;` or use a while loop, as demonstrated below
}

Это может быть чистая реализация:

do
{
   bytes = socket.Receive(...);
   // Process your data
}
while (bytes > 0);
...