Control.Invoke方法后的异步套接字发送问题

时间:2011-07-28 19:40:16

标签: c# sockets networking asynchronous asyncsocket

我有一个使用Asynchronous Socket的客户端/服务器应用程序。我有一个从服务器端向客户端发送数据的方法,客户端有一个方法来处理这些数据并控制客户端的表单控制。

由于使用Async套接字,我需要使用Control.Invoke方法来访问主线程。但是我遇到了一个问题 - 在我使用Control.Invoke后,它开始向服务器端发送数据问题。它进入socketClient.Send(byteArray);但不是将数据发送到服务器。如果我不使用Invoke.Method我无法控制客户端表单控件:(

我必须做什么?

好的我发现了我的问题,但它不是关于Control.Invoke它的套接字数据传输问题。但我无法解决它。当我使用repeadetly 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 个答案:

答案 0 :(得分:2)

第一

你没有使用异步套接字,如果那时你要么调用Socket.BeginSendSocket.SendAsync。调用Socket.Send不是异步的,事实上它是非常同步!

第二

我看不出调用方法与你无法发送数据有什么关系...你当前正在描述套接字数据传输问题,但你给我们的代码示例显示了你在主线程上调用invoke,它启动new Thread并以某种方式导致套接字转到AWOL

第三

请提供符合sscce标准的代码示例,我们可以用它来重现您的问题(至少)或提供一些更相关的代码:

  1. 如何将数据发送到服务器。
  2. 新线程中调用的代码是什么(即它对套接字做了什么?)
  3. 您在服务器端执行的操作以接收数据。
  4. 更新

    这是我的版本......我首先制作方法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的方法中隔离该调用(如我的示例所示),并且它不会对建立套接字连接执行任何操作。