2014-03-26 1 views
2

나는 서버 채팅 메신저에 클라이언트 작업을하고 있으며 비동기 호출과 관련된 몇 가지 문제가 발생했습니다. 나는 잠시 동안 그들을 고치려고 아무런 노력없이 노력해왔다.비동기식 소켓 호출 UI 고정

문제는 클라이언트와 관련이 있지만 서버에 연결하는 데 문제가 없지만 첫 번째 'BeginSend'메소드가 호출되면 전체 클라이언트가 응답을 중지합니다 (100 %는 응답하지 않지만 가끔씩은 응답하지만 우스운 응답 시간 30 초 이상). 나머지 호출은 정상적으로 작동하지만 UI는 응답하지 않습니다. 서버는 잘 응답합니다.

코드는 다음과 같습니다. 클라이언트가 먼저 멈춘 곳은 여기에 있습니다.

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using System.Windows.Forms.VisualStyles; 
using System.Net.Sockets; 
using System.Net; 

namespace Client_GUI_Design_Test 
{ 
    public partial class Login : Form 
    { 
     public Socket clientSocket; 
     public string strName; 
     public byte[] byteData = new byte[1024]; 
     public List<String> contacts = new List<String>(); 
     public Boolean needUpdate = true; 
     // public Panel globalPanel; 
     public Login() 
     { 
      InitializeComponent(); 
     } 

     public struct Contact 
     { 
      public string strName; 
     } 


     public int num1 = 0; 
     public void addContact(String contactName, String message, int status, int imageNum) 
     { 
      //MessageBox.Show(this.Size.Width.ToString()); 
      panel1.HorizontalScroll.Enabled = false; 
      panel1.HorizontalScroll.Visible = false; 
      if (num1 >= panel1.Size.Height - 47) 
      { 
       panel1.Size = new Size(257, 514); 
       this.Size = new Size(277, this.Size.Height); 
       panel1.AutoScroll = true; 
       panel1.HorizontalScroll.Enabled = false; 
       panel1.HorizontalScroll.Visible = false; 
       panel1.VerticalScroll.Visible = true; 
      } 
      panel1.VerticalScroll.Value = 0; 
      //Contact Panel 
      Panel contactPanel = new Panel(); 
      contactPanel.Size = new Size(249, 47); 
      contactPanel.Margin = new System.Windows.Forms.Padding(0, 0, 0, 0); 

      //Name Label 
      Label name = new Label(); 
      //Font 
      float size = 12.00f; 
      name.Font = new Font("Microsoft Sans Serif", size, FontStyle.Bold); 
      //Location 
      name.Location = new Point(29, 3); 
      //Size 
      name.Size = new Size(112, 20); 
      name.Text = contactName; 
      //Events 
      #region 
      name.MouseEnter += delegate 
      { 
       contactPanel.BackColor = Color.Gainsboro; 
      }; 
      name.MouseLeave += delegate 
      { 
       contactPanel.BackColor = System.Drawing.SystemColors.Control; 
      }; 
      #endregion 
      contactPanel.Controls.Add(name); 

      //Image Box 
      PictureBox image = new PictureBox(); 
      //Image 
      image.Image = imageList1.Images[imageNum]; 
      //Size 
      image.Size = new Size(56, 42); 
      //Location 
      image.Location = new Point(187, 4); 
      //Events 
      #region 
      image.MouseEnter += delegate 
      { 
       contactPanel.BackColor = Color.Gainsboro; 
      }; 
      image.MouseLeave += delegate 
      { 
       contactPanel.BackColor = System.Drawing.SystemColors.Control; 
      }; 
      #endregion 
      contactPanel.Controls.Add(image); 

      //Status 
      PictureBox statusPic = new PictureBox(); 
      //Image 
      statusPic.Image = imageList2.Images[status]; 
      //Size 
      statusPic.Size = new Size(20, 20); 
      //Location 
      statusPic.Location = new Point(3, 3); 
      //Events 
      #region 
      statusPic.MouseEnter += delegate 
      { 
       contactPanel.BackColor = Color.Gainsboro; 
      }; 
      statusPic.MouseLeave += delegate 
      { 
       contactPanel.BackColor = System.Drawing.SystemColors.Control; 
      }; 
      #endregion 
      contactPanel.Controls.Add(statusPic); 

      //Message Label 
      Label messageL = new Label(); 
      //Font 
      float sizem = 11.25f; 
      messageL.Font = new Font("Microsoft Sans Serif", sizem, FontStyle.Bold); 
      messageL.ForeColor = Color.Gray; 
      //Location 
      messageL.Location = new Point(29, 23); 
      //Size 
      messageL.Size = new Size(153, 18); 
      //Text 
      messageL.Text = message; 
      //Events 
      #region 
      messageL.MouseEnter += delegate 
      { 
       contactPanel.BackColor = Color.Gainsboro; 
      }; 
      messageL.MouseLeave += delegate 
      { 
       contactPanel.BackColor = System.Drawing.SystemColors.Control; 
      }; 
      messageL.MouseHover += delegate 
      { 
       ToolTip tip = new ToolTip(); 
       tip.Tag = messageL.Text; 
       tip.Show(messageL.Text, messageL, 1, 1, 750); 
      }; 
      #endregion 

      contactPanel.Controls.Add(messageL); 

      contactPanel.Paint += new PaintEventHandler(contactPanel_Paint); 
      { 


      }; 
      contactPanel.MouseEnter += delegate 
      { 
       contactPanel.BackColor = Color.Gainsboro; 
      }; 
      contactPanel.MouseLeave += delegate 
      { 
       contactPanel.BackColor = System.Drawing.SystemColors.Control; 
      }; 
      contactPanel.Location = new Point(0, num1); 
      //globalPanel = contactPanel; 
      //panel1.Controls.Add(contactPanel); 
      addPanel(contactPanel); 
      num1 += 47; 


     } 

     public delegate void UpdatePanelCallBack(Panel panel); 
     private void addPanel(Panel panel) 
     { 
      if (InvokeRequired) 
      { 
       object[] pList = { panel }; 
       panel1.BeginInvoke(new 
        UpdatePanelCallBack(OnUpdatePanel), pList); 
      } 

      else 
      { 
       OnUpdatePanel(panel); 
      } 
     } 

     private void OnUpdatePanel(Panel panel) 
     { 
      panel1.Controls.Add(panel); 
     } 

     VisualStyleRenderer renderer = new VisualStyleRenderer(VisualStyleElement.Button.PushButton.Normal); 
     void contactPanel_Paint(object sender, PaintEventArgs e) 
     { 
      renderer.DrawEdge(e.Graphics, panel1.ClientRectangle, 
       Edges.Top, 
       EdgeStyle.Bump, EdgeEffects.Flat); 
     } 

     private void button3_Click(object sender, EventArgs e) 
     { 
      try 
      { 
       clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 

       //IPAddress ipAddress = IPAddress.Parse(txtServerIP.Text); 
       //Server is listening on port 43594 
       IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 43594); 

       //Connect to the server 
       clientSocket.BeginConnect(ipEndPoint, new AsyncCallback(OnConnect), null); 
      } 
      catch (Exception ex) 
      { 
       MessageBox.Show(ex.Message, "SGSclient", MessageBoxButtons.OK, MessageBoxIcon.Error); 
      } 


     } 

     private void OnSend(IAsyncResult ar) 
     { 
      try 
      { 
       Socket client = (Socket)ar.AsyncState; 
       client.EndSend(ar); 
       //clientSocket.EndSend(ar); 
       //strName = textBox2.Text; 
       // DialogResult = DialogResult.OK; 
      } 
      catch (Exception ex) 
      { 
       MessageBox.Show(ex.Message, "SGSclient", MessageBoxButtons.OK, MessageBoxIcon.Error); 
      } 
     } 

     private void OnConnect(IAsyncResult ar) 
     { 
      try 
      { 
       clientSocket.EndConnect(ar); 

       //We are connected so we login into the server 
       Data msgToSend = new Data(); 
       msgToSend.cmdCommand = Command.Login; 
       msgToSend.strName = textBox2.Text; 
       msgToSend.strMessage = null; 

       byte[] b = msgToSend.ToByte(); 

       //Send the message to the server 
       //HERE - Starts freezing the UI thread, continues to do background operations 
       clientSocket.BeginSend(b, 0, b.Length, SocketFlags.None, new AsyncCallback(OnSend), clientSocket); 

       clientSocket.BeginReceive(byteData, 
             0, 
             byteData.Length, 
             SocketFlags.None, 
             new AsyncCallback(OnReceive), 
             clientSocket); 
      } 
      catch (Exception ex) 
      { 
       MessageBox.Show(ex.Message, "SGSclient", MessageBoxButtons.OK, MessageBoxIcon.Error); 
      } 

      panel4.Visible = false; 
      panel1.Visible = true; 
     } 

     public void OnReceive(IAsyncResult ar) 
     { 
      try 
      { 
       clientSocket.EndReceive(ar); 

       Data msgReceived = new Data(byteData); 
       //Accordingly process the message received 
       switch (msgReceived.cmdCommand) 
       { 
        case Command.Login: 
         //lstChatters.Items.Add(msgReceived.strName); 
         break; 

        case Command.Logout: 
         //lstChatters.Items.Remove(msgReceived.strName); 
         break; 

        case Command.Message: 
         break; 

        case Command.List: 
         MessageBox.Show(msgReceived.strName); 
         //contacts.Add(msgReceived.strName); 
         needUpdate = true; 
         //lstChatters.Items.AddRange(msgReceived.strMessage.Split('*')); 
         //lstChatters.Items.RemoveAt(lstChatters.Items.Count - 1); 
         //txtChatBox.Text += "<<<" + strName + " has joined the room>>>\r\n"; 

         break; 
       } 

       byteData = new byte[1024]; 

       clientSocket.BeginReceive(byteData, 
              0, 
              byteData.Length, 
              SocketFlags.None, 
              new AsyncCallback(OnReceive), 
              clientSocket); 

      } 
      catch (ObjectDisposedException) 
      { } 
      catch (Exception ex) 
      { 
       MessageBox.Show(ex.Message, "SGSclientTCP: " + strName, MessageBoxButtons.OK, MessageBoxIcon.Error); 
      } 

     } 

     private void Login_Load(object sender, EventArgs e) 
     { 
      CheckForIllegalCrossThreadCalls = false; 
      //backgroundWorker1.RunWorkerAsync(); 

     } 

     private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
     { 
      while (true) 
      { 
       if(needUpdate){ 

       } 
      } 
     } 


     private void Login_DoubleClick(object sender, EventArgs e) 
     { 
      MessageBox.Show(""); 
      foreach (string s in contacts) 
      { 
       addContact(s, "Random Message", 0, 1); 
       needUpdate = false; 
      } 
     } 
    } 
} 

그러나 여전히 OnReceive에 문제가 (하는 빠른에 도움이되는 문제를 식별 할 수 있음) 내가 미안 해요, 그것은 코드를 많이 알고

public void OnReceive(IAsyncResult ar) 
     { 
      try 
      { 
       Socket client = (Socket)ar.AsyncState; 
       client.EndReceive(ar); 

       Data msgReceived = new Data(byteData); 
       //Accordingly process the message received 
       switch (msgReceived.cmdCommand) 
       { 
        case Command.Login: 
         //lstChatters.Items.Add(msgReceived.strName); 
         break; 

        case Command.Logout: 
         //lstChatters.Items.Remove(msgReceived.strName); 
         break; 

        case Command.Message: 
         break; 

        case Command.List: 
         MessageBox.Show(msgReceived.strName); 
         //contacts.Add(msgReceived.strName); 
         needUpdate = true; 
         //lstChatters.Items.AddRange(msgReceived.strMessage.Split('*')); 
         //lstChatters.Items.RemoveAt(lstChatters.Items.Count - 1); 
         //txtChatBox.Text += "<<<" + strName + " has joined the room>>>\r\n"; 

         break; 
       } 

       byteData = new byte[1024]; 

       /* client.BeginReceive(byteData, 
              0, 
              byteData.Length, 
              SocketFlags.None, 
              new AsyncCallback(OnReceive), 
              client);*/ 

      } 
      catch (ObjectDisposedException) 
      { } 
      catch (Exception ex) 
      { 
       MessageBox.Show(ex.Message, "SGSclientTCP: " + strName, MessageBoxButtons.OK, MessageBoxIcon.Error); 
      } 

     } 

을, 다른 클래스에 문제를 해결하지만, 이것은 내가 완전히 붙어있는 마지막 옵션입니다. 어떤 도움을 크게 주시면 감사하겠습니다 :)

+1

이 clientSocket.BeginConnect (IPEndPoint로, 새로운 AsyncCallback (는 OnConnect), clientSocket)를보십시오; OnConnect 내부에서는 OnSend와 마찬가지로 ar.AsyncState의 소켓을 사용합니다. 다른 스레드에서 clientSocket에 액세스하고 있습니다. –

+0

@MihaiHantea 당신이 조언 한 후에 나는 대부분의 방법을 onReceive와 별개로 고칠 수있었습니다. 나는 아직도 거기에서 같은 문제를 겪고있다. –

+1

client.EndReceive (ar)를 호출하면 여전히 고정 상태가됩니까? –

답변

1

다른 스레드에서 clientSocket에 액세스하고 있습니다. button3_Click 전화 BeginConnect이처럼 소켓을 통과

내부 : (BeginConnect를 호출하면 여기에 전달)

//Connect to the server 
clientSocket.BeginConnect(ipEndPoint, new AsyncCallback(OnConnect), clientSocket); 

OnReceive 내부 AsyncState에서 소켓을 얻을 :

Socket client = (Socket)ar.AsyncState; 
client.EndReceive(ar); 

MSDN EndConnect에서 EndConnect is a blocking method that completes the asynchronous remote host connection request started in the BeginConnect method

Before calling BeginConnect, you need to create a callback method that implements the AsyncCallback delegate. This callback method executes in a separate thread and is called by the system after BeginConnect returns. The callback method must accept the IAsyncResult returned by the BeginConnect method as a parameter.

편집 :

내가 코드에서 볼 수 있듯이

, 당신의 클래스 필드로 선언하고 BeginReceive가 액세스하려고하는 다른 스레드에서 액세스 byteData 버퍼를 사용하고 있습니다. 읽기 부분을 어떻게 처리 할 수 ​​있는지 보려면 Asynchronous Server Socket Example을 확인하십시오.

당신은 MSDN의 예에서 볼 수 Socket Code Examples

Asynchronous Server Socket Example

Asynchronous Client Socket Example

+0

정말 무식하지만 유감스럽게 생각하지만 솔루션에서 벗어나는 코드는 볼 수 없습니다. 어쨌든, BeginReceive 메서드를 호출하지 않으면 코드가 실행되지 않고 계속 실행되므로 OnReceive 메서드에 문제가있을 수 있습니다. 또한 msn 예제에있는 수동 이벤트 처리기가 필요합니다. 필자는 A-Synchronicity의 목적을 무력화시킨 것처럼 느낍니다. 지금까지 도와 줘서 정말 고마워. :) –

+1

답변을 올렸습니다. 해당 byteData 버퍼를 사용하면 이전과 동일한 작업을 수행하면서 다른 스레드에서 UI 스레드가 소유 한 리소스에 액세스합니다. 예제 StateObject에서와 비슷한 클래스를 사용해보십시오. –

+0

해결책을 제공해 주셔서 감사합니다. 그러나 예제에 표시된 것과 같은 방식으로 데이터를 읽는 데 문제가 있습니다. 나는 StateObject의 새로운 인스턴스를 생성하고 내가 메인 스레드에서 리소스를 액세스하는 것처럼 당신이 그것을 도울 수 있다면 그때, 그러나 그것은 여전히 ​​얼어 ar.AsyncState에서 StateObject의 새 인스턴스를 만들 을 OnReceive하는 상태로 전달 너무 놀랄 것입니다 :) –