На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
  
> создать асинхронный сокет
    как создать асинхронный сокет?

    видел пример из MSDN, там много лишеств, в результате чего непонятно..
    да и пробовал как у них делать - не работает, точнее не срабатывает функция-делегат, когда я посылаю данные..
      Вот пример клиента(Windows приложение)
      ExpandedWrap disabled
        using System;
        using System.Drawing;
        using System.Net;
        using System.Net.Sockets;
        using System.Text;
        using System.Windows.Forms;
        class AsyncTcpClient Form:
        {
          private TextBox newText;
          private TextBox conStatus;
          private ListBox results;
          private Socket client;
          private byte[] data = new byte[1024];
          private int size = 1024;
          public AsyncTcpClient()
          {
           Text = "Asynchronous TCP Client";
           Size = new Size(400, 380);
          
           Label label1 = new Label();
           label1.Parent = this;
           label1.Text = "Enter text string:";
           label1.AutoSize = true;
           label1.Location = new Point(10, 30);
           newText = new TextBox();
           newText.Parent = this;
           newText.Size = new Size(200, 2 * Font.Height);
           newText.Location = new Point(10, 55);
           results = new ListBox();
           results.Parent = this;
           results.Location = new Point(10, 85);
           results.Size = new Size(360, 18 * Font.Height);
           Label label2 = new Label();
           label2.Parent = this;
           label2.Text = "Connection Status:";
           label2.AutoSize = true;
           label2.Location = new Point(10, 330);
           conStatus = new TextBox();
           conStatus.Parent = this;
           conStatus.Text = "Disconnected";
           conStatus.Size = new Size(200, 2 * Font.Height);
           conStatus.Location = new Point(110, 325);
           Button sendit = new Button();
           sendit.Parent = this;
           sendit.Text = "Send";
           sendit.Location = new Point(220,52);
           sendit.Size = new Size(5 * Font.Height, 2 * Font.Height);
           sendit.Click += new EventHandler(ButtonSendOnClick);
           Button connect = new Button();
           connect.Parent = this;
           connect.Text = "Connect";
           connect.Location = new Point(295, 20);
           connect.Size = new Size(6 * Font.Height, 2 * Font.Height);
           connect.Click += new EventHandler(ButtonConnectOnClick);
           Button discon = new Button();
           discon.Parent = this;
           discon.Text = "Disconnect";
           discon.Location = new Point(295,52);
           discon.Size = new Size(6 * Font.Height, 2 * Font.Height);
           discon.Click += new EventHandler(ButtonDisconOnClick);
          }
          void ButtonConnectOnClick(object obj, EventArgs ea)
          {
           conStatus.Text = "Connecting...";
           Socket newsock = new Socket(AddressFamily.InterNetwork,
                      SocketType.Stream, ProtocolType.Tcp);
           IPEndPoint iep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9050);
           newsock.BeginConnect(iep, new AsyncCallback(Connected), newsock);
          }
          void ButtonSendOnClick(object obj, EventArgs ea)
          {
           byte[] message = Encoding.ASCII.GetBytes(newText.Text);
           newText.Clear();
           client.BeginSend(message, 0, message.Length, SocketFlags.None,
                  new AsyncCallback(SendData), client);
          }
          void ButtonDisconOnClick(object obj, EventArgs ea)
          {
           client.Close();
           conStatus.Text = "Disconnected";
          }
          void Connected(IAsyncResult iar)
          {
           client = (Socket)iar.AsyncState;
           try
           {
             client.EndConnect(iar);
             conStatus.Text = "Connected to: " + client.RemoteEndPoint.ToString();
             client.BeginReceive(data, 0, size, SocketFlags.None,
                    new AsyncCallback(ReceiveData), client);
           } catch (SocketException)
           {
             conStatus.Text = "Error connecting";
           }
          }
          void ReceiveData(IAsyncResult iar)
          {
           Socket remote = (Socket)iar.AsyncState;
           int recv = remote.EndReceive(iar);
           string stringData = Encoding.ASCII.GetString(data, 0, recv);
           results.Items.Add(stringData);
          }
          void SendData(IAsyncResult iar)
          {
           Socket remote = (Socket)iar.AsyncState;
           int sent = remote.EndSend(iar);
           remote.BeginReceive(data, 0, size, SocketFlags.None,
                  new AsyncCallback(ReceiveData), remote);
          }
          public static void Main()
          {
           Application.Run(new AsyncTcpClient());
          }
        }

      Сервер
      ExpandedWrap disabled
        using System;
        using System.Drawing;
        using System.Net;
        using System.Net.Sockets;
        using System.Text;
        using System.Windows.Forms;
        class AsyncTcpSrvr    Form:
        {
          private TextBox conStatus;
          private ListBox results;
          private byte[] data = new byte[1024];
          private int size = 1024;
          private Socket server;
          public AsyncTcpSrvr()
          {
           Text = "Asynchronous TCP Server";
           Size = new Size(400, 380);
           results = new ListBox();
           results.Parent = this;
           results.Location = new Point(10, 65);
           results.Size = new Size(350, 20 * Font.Height);
           Label label1 = new Label();
           label1.Parent = this;
           label1.Text = "Text received from client:";
           label1.AutoSize = true;
           label1.Location = new Point(10, 45);
           Label label2 = new Label();
           label2.Parent = this;
           label2.Text = "Connection Status:";
           label2.AutoSize = true;
           label2.Location = new Point(10, 330);
           conStatus = new TextBox();
           conStatus.Parent = this;
           conStatus.Text = "Waiting for client...";
           conStatus.Size = new Size(200, 2 * Font.Height);
           conStatus.Location = new Point(110, 325);
           Button stopServer = new Button();
           stopServer.Parent = this;
           stopServer.Text = "Stop Server";
           stopServer.Location = new Point(260,32);
           stopServer.Size = new Size(7 * Font.Height, 2 * Font.Height);
           stopServer.Click += new EventHandler(ButtonStopOnClick);
           server = new Socket(AddressFamily.InterNetwork,
                  SocketType.Stream, ProtocolType.Tcp);
           IPEndPoint iep = new IPEndPoint(IPAddress.Any, 9050);
           server.Bind(iep);
           server.Listen(5);
           server.BeginAccept(new AsyncCallback(AcceptConn), server);
          }
          void ButtonStopOnClick(object obj, EventArgs ea)
          {
           Close();
          }
          void AcceptConn(IAsyncResult iar)
          {
           Socket oldserver = (Socket)iar.AsyncState;
           Socket client = oldserver.EndAccept(iar);
           conStatus.Text = "Connected to: " + client.RemoteEndPoint.ToString();
           string stringData = "Welcome to my server";
           byte[] message1 = Encoding.ASCII.GetBytes(stringData);
           client.BeginSend(message1, 0, message1.Length, SocketFlags.None,
                 new AsyncCallback(SendData), client);
          }
          void SendData(IAsyncResult iar)
          {
           Socket client = (Socket)iar.AsyncState;
           int sent = client.EndSend(iar);
           client.BeginReceive(data, 0, size, SocketFlags.None,
                 new AsyncCallback(ReceiveData), client);
          }
          void ReceiveData(IAsyncResult iar)
          {
           Socket client = (Socket)iar.AsyncState;
           int recv = client.EndReceive(iar);
           if (recv == 0)
           {
             client.Close();
             conStatus.Text = "Waiting for client...";
             server.BeginAccept(new AsyncCallback(AcceptConn), server);
             return;
           }
           string receivedData = Encoding.ASCII.GetString(data, 0, recv);
           results.Items.Add(receivedData);
           byte[] message2 = Encoding.ASCII.GetBytes(receivedData);
           client.BeginSend(message2, 0, message2.Length, SocketFlags.None,
                  new AsyncCallback(SendData), client);
          }
          public static void Main()
          {
           Application.Run(new AsyncTcpSrvr());
          }
        }
        а как всё это сделать для UDP, чтоб не требовалось коннекта и принятия его?

        и что если я вместо BeginConnect исполбзую просто Connect?

        можт кто посмотрит, почему не срабатывает OnReceive?

        ExpandedWrap disabled
          using System;
          using System.Drawing;
          using System.Windows.Forms;
           
          public class Canvas : System.Windows.Forms.Form
          {
              private System.Windows.Forms.ListBox listBoxField;
              private System.Windows.Forms.TextBox textBoxMessage;
              private System.Windows.Forms.Button buttonSend;
           
              public Canvas()
              {
                  InitializeComponent();
                  Core.InitializeServer();
              }
           
              #region Windows Form Designer generated code
              private void InitializeComponent()
              {
                  this.listBoxField = new System.Windows.Forms.ListBox();
                  this.textBoxMessage = new System.Windows.Forms.TextBox();
                  this.buttonSend = new System.Windows.Forms.Button();
                  this.SuspendLayout();
                  //
                  // listBoxField
                  //
                  this.listBoxField.Location = new System.Drawing.Point(8, 8);
                  this.listBoxField.Name = "listBoxField";
                  this.listBoxField.Size = new System.Drawing.Size(392, 186);
                  this.listBoxField.TabIndex = 0;
                  //
                  // textBoxMessage
                  //
                  this.textBoxMessage.Location = new System.Drawing.Point(16, 208);
                  this.textBoxMessage.Name = "textBoxMessage";
                  this.textBoxMessage.Size = new System.Drawing.Size(296, 20);
                  this.textBoxMessage.TabIndex = 1;
                  this.textBoxMessage.Text = "";
                  //
                  // buttonSend
                  //
                  this.buttonSend.Location = new System.Drawing.Point(320, 208);
                  this.buttonSend.Name = "buttonSend";
                  this.buttonSend.Size = new System.Drawing.Size(72, 24);
                  this.buttonSend.TabIndex = 2;
                  this.buttonSend.Text = "SEND";
                  this.buttonSend.Click += new System.EventHandler(this.buttonSend_Click);
                  //
                  // Canvas
                  //
                  this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
                  this.ClientSize = new System.Drawing.Size(408, 243);
                  this.Controls.Add(this.buttonSend);
                  this.Controls.Add(this.textBoxMessage);
                  this.Controls.Add(this.listBoxField);
                  this.Name = "Canvas";
                  this.Text = "Form1";
                  this.ResumeLayout(false);
           
              }
              #endregion
           
              [STAThread]
              static void Main()
              {
                  Application.Run(new Canvas());
              }
           
              private void buttonSend_Click(object sender, System.EventArgs e)
              {
                  Core.Send(textBoxMessage.Text);
              }
           
              public static void OnReceive(IAsyncResult iar)
              {
                  System.Net.Sockets.Socket remote = (System.Net.Sockets.Socket)iar.AsyncState;
                  int recv = remote.EndReceive(iar);
                  byte[] data = new byte[1024];
                  string stringData = System.Text.Encoding.ASCII.GetString(data, 0, recv);
                  //results.Items.Add(stringData);
                  MessageBox.Show(stringData);
              }
          }
           
          using System;
          using System.Text;
          using System.Net;
          using System.Net.Sockets;
          using System.Windows.Forms;
           
          public class Core
          {
              private static Socket socketServer = null;
              private static Socket socketClient = null;
              private static byte[] data = new byte[1024];
              private static int size = 1024;
           
              public static void InitializeServer()
              {
                  socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                  try
                  {
                      socketServer.Connect(new IPEndPoint(IPAddress.Loopback, 30000));
                      socketServer.BeginReceive(data, 0, size, SocketFlags.None,
                          new AsyncCallback(Canvas.OnReceive), socketServer);
           
                  }
                  catch (Exception e)
                  {
                      MessageBox.Show(e.ToString());
                  }
              }
           
              public static void Send(string s)
              {
                  socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                  try
                  {
                      socketClient.Connect(new IPEndPoint(IPAddress.Loopback, 30000));
                      socketClient.Send(Encoding.ASCII.GetBytes(s));
                  }
                  catch (Exception e)
                  {
                      MessageBox.Show(e.ToString());
                  }
              }
          }
        Сообщение отредактировано: Nemesis -
          Цитата
          а как всё это сделать для UDP, чтоб не требовалось коннекта и принятия его?

          Коннект требуется везде. и соответственно принятие его тоже. Протоколы TCP и UDP отличаются лишь тем, что TCP более надежен, а UPD - нет. Но UDP соответственно будет работать быстрее.
          Чтобы использовать UDP, достаточно заменить:
          ExpandedWrap disabled
            Socket newsock = new Socket(AddressFamily.InterNetwork,
                          SocketType.Stream, ProtocolType.Tcp);

          на:
          ExpandedWrap disabled
            Socket newsock = new Socket(AddressFamily.InterNetwork,
                          SocketType.Stream, ProtocolType.Udp);

          в клиенте и сервере.

          Цитата
          и что если я вместо BeginConnect исполбзую просто Connect?

          Connect коннектится к серверу используя синхронный сокет. Т.е. поток в твоей программе остановится, и программа зависнет, пока соединение не установится. А BeginConnect использует именно асинхронные сокеты, для установки соединения. Т.е. пока соединение будет устанавливаться, твоя программа будет спокойно работать дальше.
          Чтобы отлавливать установку соединения, ф-ия BeginConnect вызывает событие. Наша задача, отлавить и отреагировать на это событие. Обработчик события(т.е. простую ф-ия, которая будет ваызываться при установки соединения) мы передаем как параметр методу BeginConnect:
          ExpandedWrap disabled
            newsock.BeginConnect(iep, new AsyncCallback(Connected), newsock);

          В данном случае это будет метод Connected.
          Метод Connected должен принимать параметр IAsyncResult. Через этот парамерт мы сможем получить сокет с установленным соединением:
          ExpandedWrap disabled
            void Connected(IAsyncResult iar)
              {
               client = (Socket)iar.AsyncState;// Получает сокет с соединением
               try
               {
                 client.EndConnect(iar);// Прекращаем попытки установить соединение через главный сокет
                 // теперь, зная, что сервер сразу после установки соединения с ним посылает данные, принимаем их,    
            //через установленный сокет и записываем в массив data .
                 client.BeginReceive(data, 0, size, SocketFlags.None,
                        new AsyncCallback(ReceiveData), client);
               } catch (SocketException)
               {
                 // Ошибка при установке соединения
                 conStatus.Text = "Error connecting";
               }
              }

          В этом примере, мы получаем сокет через параметр iar, и вызываем метод BeginReceive, чтобы получить ответ от сервера. BeginReceive также использует асинхронные сокеты, чтобы получить ответ. И в данном случае, вызывает ф-ию ReceiveData, когда соединится и получит ответ.
          ExpandedWrap disabled
            void ReceiveData(IAsyncResult iar)
              {
               Socket remote = (Socket)iar.AsyncState;// получаем сокет с установленным соединением.
               int recv = remote.EndReceive(iar);// прекращаем получать данные.
               string stringData = Encoding.ASCII.GetString(data, 0, recv);// получаем строку из масства data
               results.Items.Add(stringData);
              }

          С сервером таже история, только вместо BeginConnect надо использовать BeginAccept и т.д.
          Сообщение отредактировано: Gazon -
            Gazon,
            Цитата
            Коннект требуется везде. и соответственно принятие его тоже

            Это не так - особенно насчет принятия.
            Функция connect() является функцией активного запроса на соединение с удаленным TCP-сервером, поэтому эта функция как правило размещается в программном коде TCP-клиента (ориентированный на соединение сокет.)
            Однако эту функцию можно также использовать и при передаче данных через неориентированный на соединение сокет, например по протоколу UDP или для простых (raw) сокетов, после чего на этих сокетах можно исполнять функции send() и recv(), типичные для потоковой передачи. Фактически в этом случае функция connect() заменяет функцию bind(). Но процедура threeway handshake не будет выполняться, т.к. ее в протоколе UDP нет.
            Функция connect(), вызванная для UDP-сокета, жестко привяжет к этому сокету структуру адреса удаленного хоста, и в вызове sendto() для этого сокета мы уже не сможем в структуре, расположенной по адресу socket_address_structure, указать какой-то другой адрес.
            Обычно и клиент, и сервер протокола UDP выполняют connect(), если они устанавливают "долговременное соединение" для обмена информацией, например по протоколу TFTP. Второй пример – это клиент службы DNS на протоколе UDP, он тоже может быть зафиксирован на одном DNS-сервере с помощью вызова connect().
            Цитата
            SocketType.Stream, ProtocolType.Udp);

            По закону здесь должен быть стиль связи SOCK_DGRAM?
            Сообщение отредактировано: Oleg2004 -
              Цитата
              Это не так - особенно насчет принятия

              Точно. Я про это забыл.
              Цитата
              По закону здесь должен быть стиль связи SOCK_DGRAM?

              Да.
              ExpandedWrap disabled
                (AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)
                :huh:
                а как мне тогда отсылать широковещательные сообщения?
                коннектиться клиентом на 255.255.255.255?
                  Nemesis,
                  Цитата
                  коннектиться клиентом на 255.255.255.255?

                  1. Приложение - т.е. ваша программа - должна на сокете, по которому будет идти широковещательная передача, установить опцию сокетов SO_BROADCAST. Это булевская опция, "ДА-НЕТ", устанавливается с помощью функции сокетов setsockopt().
                  Если у вас среда .NET, то надо смотреть, поддерживается ли эта опция - тут я не спец.
                  Она управляет возможностью отправки широковещательных сообщений. Широковещательная передача поддерживается только для сокетов дейтаграмм (в данном случае только UDP и только в сетях, поддерживающих концепцию широковещательных сообщений (Ethernet, Token Ring и т. д.).
                  Широковещательная передача в соединении типа «точка-точка» (TCP) неосуществима.
                  Следовательно, не о каком connect() речи идти не может. Поскольку перед отправкой широковещательной дейтаграммы приложение должно установить этот параметр сокета, оно не сможет отправить широковещательное сообщение, если это не предполагалось заранее. Например, приложение UDP может принять IP-адрес получателя в качестве аргумента командной строки, но оно может и не предполагать, что пользователь вводит широковещательный адрес. Проверку того, является или нет данный адрес широковещательным адресом, осуществляет не приложение, а ядро: если адрес получателя является широковещательным адресом и данный параметр сокета не установлен, возвратится ошибка EACCESS
                  Сообщение отредактировано: Oleg2004 -
                  0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                  0 пользователей:


                  Рейтинг@Mail.ru
                  [ Script execution time: 0,0415 ]   [ 17 queries used ]   [ Generated: 18.04.24, 15:41 GMT ]