0

非同期ソケットを使用するクライアント/サーバーアプリケーションがあります。サーバー側からクライアントにデータを送信する方法があり、クライアントはこのデータを処理してクライアントのフォーム制御を制御する方法を持っています。

非同期ソケットを使用しているため、Control.Invokeメインスレッドにアクセスするためのメソッドを使用する必要があります。しかし、問題が発生しました。使用するControl.Invokeと、サーバー側へのデータ送信の問題が発生します。それはsocketClient.Send(byteArray);に入ります。ただし、サーバーにデータを送信しません。Invoke.Methodを使用しない場合、クライアント側のフォームコントロールを制御できません:(

私がしなければならないこと?

問題は見つかりましたが、Controlに関するものではありません。ソケットデータ送信の問題を呼び出しますが、解決できませんでした。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.BeginSendまたはSocket.SendAsyncのいずれかを呼び出します。呼び出しSocket.Sendは非同期ではありません。実際のところ、呼び出しは非常に同期的です。

2番

invokeメソッドがデータを送信できないことと何の関係があるのか​​わかりません...あなたは現在ソケットデータ送信の問題を説明していますが、invokeを呼び出すことを示すコードサンプルを提供しています開始するメインスレッドとnew Thread、どういうわけかソケットがAWOLになる原因になります!

第3

(少なくとも)問題を再現するために使用できる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の呼び出しのみを処理するメソッドでその呼び出しを分離する必要があり、ソケット接続の確立には何もしません。

于 2011-07-28T21:45:17.593 に答える