Асинхронно на сокетах скачать несколько html страничек

Рейтинг: 0Ответов: 2Опубликовано: 21.04.2011

Собственно сабж. Если есть пример буду очень благодарен. Везде для сокетов описывается клиент-сервер, никак не могу понять общую картину как это делается, мне просто нужно получить код страницы, неужели для этого нужен клиент-сервер?

UPD: есть пример, но он только для одного запроса

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Windows.Forms;

namespace AsyncSocketExample
{
  public partial class Form1 : Form
  {
    private delegate void MyDelegate(object args);

    public Form1()
    {
      InitializeComponent();
    }

    private void GetHtmlAsynh(string adress) //все что в этом методе было раньше в обработчике кнопки
    {
      if (String.IsNullOrEmpty(adress))
      {
        MessageBox.Show("Необходимо указать url!", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
      }

      int port = 80; // по умолчанию порт 80
      Uri u = new Uri(textBox1.Text);

      // создаем сокет
      Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

      // инициализируем обработчик асихронных операций
      SocketAsyncEventArgs se = new SocketAsyncEventArgs();
      // подключаем обработчики событий асинхронных запросов
      se.Completed += new EventHandler<SocketAsyncEventArgs>(OnSend);

      // цепляем точку доступа
      IPHostEntry hostEntry = Dns.GetHostEntry(u.Host);
      se.RemoteEndPoint = new IPEndPoint(hostEntry.AddressList[0], port);

      //se.UserToken = s;
      // создаем асихронное подключение
      s.ConnectAsync(se);
    }

    private void button1_Click(object sender, EventArgs e) 
    {
      GetHtmlAsynh(textBox1.Text);
    }

    // обработчик асинхронных операций
    private string _requestResult = "";
    private int total = 0;

    private void OnSend(object sender, SocketAsyncEventArgs e)
    {
      Socket s = (Socket)sender; // в sender будет передаваться экземпляр сокета, вызвавшего это событие

      // выводим информацию о текущей операции и результатах её выполнения
      if (e.SocketError == SocketError.Success)
      {
        //SetLabel(String.Format("Операция {0} успешно выполнена!", e.LastOperation));
      }
      else
      {
        SetLabel(String.Format("Ошибка {1} при выполнении операции {0}...", e.LastOperation, e.SocketError));
      }
      // --

      // делаем что-нибудь, в зависимости от типа выполненной операции
      switch (e.LastOperation)
      {
        case SocketAsyncOperation.Connect:
          // если соединение установлено
          if (e.SocketError == SocketError.Success)
          { // отправляем запрос
            SendRequest(s, e);
          }
          break;

        case SocketAsyncOperation.Send:
          // если запрос отправлен без ошибок
          if (e.SocketError == SocketError.Success)
          { // получаем ответ от удаленного сервера
            byte[] buffer = new byte[4096];// размер пакета 4 кб
            e.SetBuffer(buffer, 0, buffer.Length);
            // аннулируем предыдущий результат, если был
            _requestResult = "";
            total = 0;
            // получаем пачку ответа
            s.ReceiveAsync(e);
          }
          break;

        case SocketAsyncOperation.Receive:
          if (e.SocketError == SocketError.Success)
          {
            SetLabel(String.Format("Операция {0} успешно выполнена! Получено {1} байт, всего {2} байт", e.LastOperation, e.BytesTransferred, total + e.BytesTransferred));
            // передаем результат в TextBox
            _requestResult += Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred);
            total += e.BytesTransferred;
            // слудующая пачка данных, если есть
            if (e.BytesTransferred > 0)
            {
              // нужно обнулить буфер, иначе куски данных могут попасть в следующий ответ
              byte[] buffer = new byte[4096];
              e.SetBuffer(buffer, 0, buffer.Length);
              s.ReceiveAsync(e);
            }
            else
            {
              // нет данных, отключаемся
              s.Close();
              textBox2.Invoke(new Action(() => { textBox2.Text = _requestResult; }));
            }
          }
          break;
      }
    }

    // метод отправляет запрос
    private void SendRequest(Socket s, SocketAsyncEventArgs e)
    {
      // формируем HTTP-запрос
      Uri u = new Uri(textBox1.Text);
      string request = "GET " + u.PathAndQuery + " HTTP/1.1\r\nHost: " + u.Host + "\r\nConnection: Close\r\n\r\n";
      Byte[] buffer = Encoding.ASCII.GetBytes(request);
      e.SetBuffer(buffer, 0, buffer.Length);
      // отправляем асинхронный запрос
      s.SendAsync(e);
    }

    // изменение label-а, находящегося в основном потоке
    private void SetLabel(object args)
    {
      if (this.InvokeRequired)
      {
        this.Invoke(new MyDelegate(SetLabel), args);
        return;
      }
      label2.Text = args.ToString();
    }
  }
}

Коротко: textBox1 содержит url, в textBox2 выводится информация (но мне все равно куда, главное - чтобы из каждого сокета, если их несколько, получить информацию). Подскажите, пожалуйста, как запустить несколько сокетов одновременно и принять данные от них?

Ответы

▲ 2

в документации для Socket в MSDN первым лежит вот такой клевый пример: http://msdn.microsoft.com/ru-ru/library/system.net.sockets.socket.aspx в нем уже есть готовый HTTP/GET, в вашем случае я бы сделал на основе него класс с внешним событием, например HTMLLoaded, которое будет срабатывать при завершении приема странички, затем создаем для каждого урла свой экземпляр класса и подписываемся на этот ивент, далее остается обрабатывать эти вызовы

для полноценной асинхронности лучше чтоб методы ConnectSocket() и SendRecieve() запускались в собственных потоках

▲ 2

Писал клиента под веб камеру(клиенту нужен был простенький клиент на С++)

Делалось так

1 - написан "сервер" живущий на 127.0.0.1:80 , из FireFox запрошен ресурс "http://127.0.0.1/test.txt", полученый пакет сохранен в виде текста.

2 - читаем документацию на HTTP, что бы окончательно разобраться с полученым в пункте 1 пакетом, в этот момент приходит осазнание что все не так уж и сложно

Итог: выяснил, что бы получить ресурс надо "создать соединение на 80 порт сервера"=>"послать туда HTTP запрос"=>"получить(по тому же самому соединению) ответ от сервера"=>"закрыть соединение(если продолжать работать, то не обязательно)" Ответ сервера это заголовок + тело ресурса, или просто заголовок, в котором сказано что ресурса не будет :)