2017-08-31 86 views
1

我已经创建了一个局域网聊天应用程序,使用基于C#网络编程中的代码 - Richard Blum。但是,当我运行程序(我打开2窗口聊天应用程序)时,单击连接在一侧,并突然代码崩溃,并出现错误“附加信息:跨线程操作无效:从线程以外的线程访问的控制'lst_show'它被创建。“聊天应用程序c#安全线程

有人帮助我,我在这里试了几个小时,但仍然无法解决它。

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

namespace Chat_Threads 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void Form1_Load(object sender, EventArgs e) 
     { 

     } 
     private static TextBox newText = new TextBox(); 
     private static ListBox results = new ListBox(); 
     private static Socket client; 
     private static byte[] data = new byte[1024]; 


     private void btn_listen_Click(object sender, EventArgs e) 
     { 
      lst_show.Items.Add("Listening for a client..."); 

      Socket newsock = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp); 

      IPEndPoint iep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9050); 

      newsock.Bind(iep); 

      newsock.Listen(5); 

      newsock.BeginAccept(new AsyncCallback(AcceptConn),newsock); 


     } 

     private void AcceptConn(IAsyncResult ar) 
     { 
      Socket oldserver = (Socket)ar.AsyncState; 

      client = oldserver.EndAccept(ar); 

      lst_show.Items.Add("Connection from: " + client.RemoteEndPoint.ToString()); 

      Thread receiver = new Thread(new ThreadStart(ReceiveData)); 

      receiver.Start(); 
     } 

     private void ReceiveData() 
     { 
      int recv; 
      string stringData; 
      while (true) 
      { 
       recv = client.Receive(data); 
       stringData = Encoding.ASCII.GetString(data, 0, recv); 
       if (stringData == "bye") 
        break; 
       lst_show.Items.Add(stringData); 
      } 
      stringData = "bye"; 
      byte[] message = Encoding.ASCII.GetBytes(stringData); 
      client.Send(message); 
      client.Close(); 
      lst_show.Items.Add("Connection stopped"); 
      return; 
     } 

     private void btn_connect_Click(object sender, EventArgs e) 
     { 
      lst_show.Items.Add("Connecting..."); 

      client = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp); 

      IPEndPoint iep = new IPEndPoint(IPAddress.Parse("127.0.0.1"),9050); 

      client.BeginConnect(iep, new AsyncCallback(Connected),client); 
     } 

     private void Connected(IAsyncResult ar) 
     { 
      try 
      { 
       client.EndConnect(ar); 

       this.lst_show.Items.Add("Connected to: " + client.RemoteEndPoint.ToString()); 

       Thread receiver = new Thread(new ThreadStart(ReceiveData)); 
       receiver.Start(); 

      } 
      catch (SocketException) 
      { 
       this.lst_show.Items.Add("Error connecting"); 
      } 
     } 

     private void btn_send_Click(object sender, EventArgs e) 
     { 
      byte[] message = Encoding.ASCII.GetBytes(txt_message.Text); 

      txt_message.Clear(); 

      client.BeginSend(message, 0, message.Length, 0, new AsyncCallback(SendData),client); 

     } 

     private void SendData(IAsyncResult ar) 
     { 
      Socket remote = (Socket)ar.AsyncState; 
      int sent = remote.EndSend(ar); 
     } 


    } 
} 
+1

只是为了记录在案,这是一本书,从2002年.... – Hackerman

+0

是的,这是非常过时。 –

回答

0

来电者是在不同的线程,这样你将不得不确保该列表,主UI线程呼叫者所以下面

control.Invoke需要。

 delegate void UpdateStringinTheGrid(string s); 

     private void ListAddItem(string s) 
     { 
      if (lst_show.InvokeRequired()) 
      { 
       var updateDel = new UpdateStringinTheGrid(ListAddItem); 
       this.BeginInvoke(updateDel, s); 
      } 
      else 
      lst_show.Items.Add(s); 

} 
    private void ReceiveData() 
      { 
       int recv; 
       string stringData; 
       while (true) 
       { 
        recv = client.Receive(data); 
        stringData = Encoding.ASCII.GetString(data, 0, recv); 
        if (stringData == "bye") 
         break; 
        listAddString(stringData); 
       } 
       stringData = "bye"; 
       byte[] message = Encoding.ASCII.GetBytes(stringData); 
       client.Send(message); 
       client.Close(); 
       lst_show.Items.Add("Connection stopped"); 
       return; 
      } 
+0

谢谢斯图尔特史密斯。我从2003年开始使用旧书,所以很多事情都发生了变化,我没有遵循。 –

+0

很高兴我能帮到你 –

0

大多数UI引擎都有一个主线程和一个专门的处理循环来更新用户界面。这是因为,如果多个线程尝试进行更改,那可能会造成竞争状态或死锁。

您的业务逻辑通常运行在一个单独的线程上,特别是当您执行诸如TCP/IP通信时。当业务逻辑需要对UI进行更改时,它会以间接方式执行此操作,例如将消息放入队列或调用特殊方法。

在.NET中,您可以使用Invoke方法在主UI线程中运行代码,然后在出现机会时安全地执行代码。例如:

lst_show.Items.Invoke((MethodInvoker)delegate 
{ 
    lst_show.Items.Add("Connection from: " + client.RemoteEndPoint.ToString()); 
});