Проблема асинхронной отправки через сокет после метода Control.Invoke - PullRequest
0 голосов
/ 28 июля 2011

У меня есть клиент-серверное приложение, которое использует асинхронный сокет. У меня есть метод для отправки данных клиенту со стороны сервера, а у клиента есть метод для обработки этих данных и управления клиентскими формами.

Из-за использования асинхронного сокета мне нужно использовать метод Control.Invoke для доступа к основному потоку.Но у меня возникла проблема - после использования Control.Invoke начинается проблема с отправкой данных на серверную часть.Его получить в socketClient.Send (byteArray);но не отправка данных на сервер.Если я не использую Invoke.Method, я не могу контролировать элементы управления на стороне клиента :(

Что мне нужно сделать?

Хорошо, я нашел свою проблему, но это не касается Control.Invoke этоПроблема с передачей данных через сокет. Но я не могу ее решить. Когда я использую метод socketClient.Send () только сначала, то сначала работает socketclient.Send (), а не мой. Вот мои коды;

// Когда клиентподключено, этот метод работает.

void baglantiSaglandi(IAsyncResult sonuc){
  try
  {


    Aday gelenAday = new Aday();
    bagliAdayListesi.Add(gelenAday);
    gelenAday.adaySoket = serverSocket.EndAccept(sonuc);

    TamponTemizle();

    // Client'in gönderdiği veriyi kabul edip, boyutunu gelendataBoyutu isimli değişkene atadık.
    int gelendataBoyutu = gelenAday.adaySoket.Receive(tampon);
    // Client'in ip adresini ipadresi property imize ekledik.
    gelenAday.ipAdresi = Mesaj(StringeDonustur(tampon, gelendataBoyutu));
    lstKullanicilar.Items.Add(gelenAday.ipAdresi);

    grpYonetim.Enabled = true;
    lblUyari.Visible = false;
    serverSocket.BeginAccept(new AsyncCallback(baglantiSaglandi), null);

    TamponTemizle();

    gelenAday.adaySoket.BeginReceive(tampon, 0, tampon.Length, SocketFlags.None, new AsyncCallback(mesajGeldi), gelenAday);
  }
  catch (SocketException ex)
  {

    MessageBox.Show(ex.Message);
  }
}

// Когда клиенты отправляют сообщение на сервер, этот блок кода работает.

void mesajGeldi(IAsyncResult sonuc){
  Aday stateAday = sonuc.AsyncState as Aday;

  try
  {

    int gelenDataBoyutu = stateAday.adaySoket.EndReceive(sonuc);
    MesajKontrol(StringeDonustur(tampon, gelenDataBoyutu), stateAday.ipAdresi);

  }
  catch (SocketException ex)
  {
    if (ex.SocketErrorCode == SocketError.ConnectionReset)
    {
      foreach (Aday cikanAday in bagliAdayListesi)
      {
        if (cikanAday.ipAdresi == stateAday.ipAdresi)
        {
          cikanAday.adaySoket.Close();
          bagliAdayListesi.Remove(cikanAday);
          //  lstKullanicilar.Items.Remove(cikanAday.ipAdresi);
          if (lstKullanicilar.Items.Count <= 0)
          {
            grpYonetim.Enabled = false;
            lblUyari.Visible = true;
          }

          break;

        }
      }
    }


  }
}

// этот метод обрабатывает сообщения клиента

void MesajKontrol(string mesaj, string aday)
{

  if (mesaj.Length < 1)
    return;

  switch (mesaj.Substring(0, 3))
  {


    case "/s/":

      string[] yanlisDogru = Mesaj(mesaj).Split(',');

      foreach (Aday cikanAday in bagliAdayListesi)
      {
        if (cikanAday.ipAdresi == aday)
        {
          lstKullanicilar.Items[bagliAdayListesi.IndexOf(cikanAday)].SubItems.Add(yanlisDogru[1]);
            lstKullanicilar.Items[bagliAdayListesi.IndexOf(cikanAday)].SubItems.Add(yanlisDogru[0]);

        }
      }

      break;

    case "/q/":
      foreach (Aday cikanAday in bagliAdayListesi)
      {
        if (cikanAday.ipAdresi == aday)
        {
          cikanAday.adaySoket.Close();
          bagliAdayListesi.Remove(cikanAday);
          //lstKullanicilar.Items.Remove(cikanAday.ipAdresi);
          if (lstKullanicilar.Items.Count <= 0)
          {
            grpYonetim.Enabled = false;
            lblUyari.Visible = true;
          }
          break;

        }
      }
      break;
    case "/b/":

      foreach (Aday cikanAday in bagliAdayListesi)
      {
        if (cikanAday.ipAdresi == aday)
        {

          lstKullanicilar.Items[bagliAdayListesi.IndexOf(cikanAday)].SubItems.Add(Mesaj(mesaj));
          lstKullanicilar.Items[bagliAdayListesi.IndexOf(cikanAday)].SubItems.Add("0");
          lstKullanicilar.Items[bagliAdayListesi.IndexOf(cikanAday)].SubItems.Add("0");

        }
      }

      break;



    default:
      break;

  }

} 

// Этот блок кода работает на стороне клиента, и здесь начинаются проблемы. 2 Метод Send работает, но на сервере выполняется только первый.

private void btnYazdir_Click(object sender, EventArgs e)
    {
      clientSocket.Send(ByteArrayeDonustur("/s/" + yanlis.ToString() + "," + dogru.ToString()));
      clientSocket.Send(ByteArrayeDonustur("/b/" + txtAdSoyad.Text));
    }

1 Ответ

2 голосов
/ 29 июля 2011

Первый

Вы не используете асинхронные сокеты, в противном случае вы бы либо вызывали Socket.BeginSend или Socket.SendAsync . Вызов Socket.Send не является асинхронным, фактически это ОЧЕНЬ синхронно!

Второй

Я не вижу, что метод invoke имеет отношение к тому, что вы тоже не можете отправлять данные ... вы сейчас описываете проблему передачи данных через сокет, но вы даете нам пример кода, который показывает вам вызывающий вызов в главном потоке, который запускает new Thread и каким-то образом заставляет сокет идти AWOL !

Третий

Пожалуйста, предоставьте пример кода, совместимого с sscce , который мы можем использовать, чтобы воспроизвести вашу проблему (как минимум), или предоставить более подходящий код в отношении:

  1. Как вы отправляете данные на сервер.
  2. Что делает код, вызванный в новом потоке (т. Е. Делает ли он что-нибудь с сокетом?)
  3. Что вы делаете на стороне сервера для получения данных.

Обновление:

Вот моя версия ... Я начинаю с создания метода BeginReceive. Он устанавливает получение сокета и вызывает метод BeginReceive для сокета:

private void BeginReceive()
{
    if ( _clientState == EClientState.Receiving)
    {
        if (_asyncTask.BytesReceived != 0 && _asyncTask.TotalBytesReceived <= _maxPageSize)
        {
            SocketAsyncEventArgs e = new SocketAsyncEventArgs();
            e.SetBuffer(_asyncTask.ReceiveBuffer, 0, _asyncTask.ReceiveBuffer.Length);
            e.Completed += new EventHandler<SocketAsyncEventArgs>(ReceiveCallback);
            e.UserToken = _asyncTask.Host;

            bool comletedAsync = false;
            try
            {
                comletedAsync = _socket.ReceiveAsync(e);
            }
            catch (SocketException se)
            {
                Console.WriteLine("Error receiving data from: " + _asyncTask.Host);
                Console.WriteLine("SocketException: {0} Error Code: {1}", se.Message, se.NativeErrorCode);

                ChangeState(EClientState.Failed);
            }

            if (!comletedAsync)
            {
                // The call completed synchronously so invoke the callback ourselves
                ReceiveCallback(this, e);
            }
        }
        else
        {
            //Console.WriteLine("Num bytes received: " + _asyncTask.TotalBytesReceived);
            ChangeState(EClientState.ReceiveDone);
        }
    }
}

Это обратный вызов приема (обратите внимание, что он снова вызывает BeginReceive):

private void ReceiveCallback(object sender, SocketAsyncEventArgs args)
{
    lock (_sync) // re-entrant lock
    {
        // Fast fail: should not be receiving data if the client
        // is not in a receiving state.
        if (_clientState == EClientState.Receiving)
        {
            String host = (String)args.UserToken;

            if (_asyncTask.Host == host && args.SocketError == SocketError.Success)
            {
                try
                {
                    Encoding encoding = Encoding.ASCII;
                    _asyncTask.BytesReceived = args.BytesTransferred;
                    _asyncTask.TotalBytesReceived += _asyncTask.BytesReceived;
                    _asyncTask.DocSource += encoding.GetString(_asyncTask.ReceiveBuffer, 0, _asyncTask.BytesReceived);

                    BeginReceive(); // <---- THIS IS WHAT YOU'RE MISSING
                }
                catch (SocketException e)
                {
                    Console.WriteLine("Error receiving data from: " + host);
                    Console.WriteLine("SocketException: {0} Error Code: {1}", e.Message, e.NativeErrorCode);

                    ChangeState(EClientState.Failed);
                }
            }
            else if (_asyncTask.Host != host)
            {
                Console.WriteLine("Warning: received a callback for {0}, but the client is currently working on {1}.",
                    host, _asyncTask.Host);
            }
            else
            {
                Console.WriteLine("Socket Error: {0} when receiving from {1}",
                   args.SocketError,
                   _asyncTask.Host);
                ChangeState(EClientState.Failed);
            }
        }
    }
}

Другими словами, вы называете это:

gelenAday.adaySoket.BeginReceive(tampon, 0, tampon.Length, SocketFlags.None, new AsyncCallback(mesajGeldi), gelenAday);

В mesajGeldi вы должны вызывать функцию, которая вызывает вышеуказанный метод. Вы должны изолировать этот вызов в методе, который заботится только о запуске begin / receive (как показано в моем примере), и он ничего не делает с установлением сокетного соединения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...