0

我有一个使用异步套接字的客户端/服务器应用程序。我有一个从服务器端向客户端发送数据的方法,客户端有一个处理这些数据和控制客户端表单控件的方法。

由于使用异步套接字,我需要使用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));
    }
4

1 回答 1

2

第一的

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

第二

我看不出调用方法与您无法发送数据有什么关系...您当前正在描述套接字数据传输问题,但您给我们提供了一个代码示例,显示您调用调用启动 anew Thread并以某种方式导致套接字退出的主线程!

第三

请提供一个符合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中,您应该调用调用上述方法的函数。您应该将该调用隔离在一个只负责调用开始/接收的方法中(如我的示例所示),并且它对建立套接字连接没有任何作用。

于 2011-07-28T21:45:17.593 回答