2016-10-22 88 views
0

當我按下發送按鈕TCP客戶端時,它會停止TCP服務器並引發此錯誤。爲什麼我的對象被另一個線程使用?

調用線程無法訪問此對象,因爲不同的 線程擁有它。

我試過調試它,但無法找到問題。 我該如何解決這個問題,因爲它很麻煩我,我是TCP/IP和線程的新手。 我知道它是如何工作,但是。

在listenerThread()方法中,它引發了這個錯誤。

lbConnections.Items.Add(handlerSocket.RemoteEndPoint.ToString() + " connected."); 

using System; 
using System.Collections; 
using System.IO; 
using System.Net; 
using System.Net.Sockets; 
using System.Threading; 
using System.Windows; 
using System.Windows.Forms; 
using System.Text; 


namespace SimpleTCPServer 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     private ArrayList nSockets; 
     public MainWindow() 
     { 
      InitializeComponent(); 
     } 

     private void Window_Loaded(object sender, RoutedEventArgs e) 
     { 

      IPHostEntry IPHost = Dns.GetHostByName(Dns.GetHostName()); 
      lblStatus.Content = "My IP address is " + IPHost.AddressList[0].ToString(); 
      nSockets = new ArrayList(); 
      Thread thdListener = new Thread(new ThreadStart(listenerThread)); 
      thdListener.Start(); 
     } 


     public void listenerThread() 
     { 
      TcpListener tcpListener = new TcpListener(8080); 
      tcpListener.Start(); 
      while (true) 
      { 
       Socket handlerSocket = tcpListener.AcceptSocket(); 
       if (handlerSocket.Connected) 
       { 
        Control.CheckForIllegalCrossThreadCalls = false; 
        lbConnections.Items.Add(handlerSocket.RemoteEndPoint.ToString() + " connected."); 
        lock (this) 
        { 
         nSockets.Add(handlerSocket); 
        } 
        ThreadStart thdstHandler = new 
        ThreadStart(handlerThread); 
        Thread thdHandler = new Thread(thdstHandler); 
        thdHandler.Start(); 
       } 
      } 
     } 

     public void handlerThread() 
     { 
      Socket handlerSocket = (Socket)nSockets[nSockets.Count - 1]; 
      NetworkStream networkStream = new NetworkStream(handlerSocket); 
      int thisRead = 0; 
      int blockSize = 1024; 
      Byte[] dataByte = new Byte[blockSize]; 
      lock (this) 
      { 
       // Only one process can access 
       // the same file at any given time 
       Stream fileStream = File.OpenWrite("c:\\my documents\\SubmittedFile.txt"); 
       while (true) 
       { 
        thisRead = networkStream.Read(dataByte, 0, blockSize); 
        fileStream.Write(dataByte, 0, thisRead); 
        if (thisRead == 0) break; 
       } 
       fileStream.Close(); 
      } 
      lbConnections.Items.Add("File Written"); 
      handlerSocket = null; 
     } 

    } 
} 

TCP客戶端

using Microsoft.Win32; 
using System.IO; 
using System.Net.Sockets; 
using System.Windows; 
using System.Threading; 
using System.Net; 
using System.Text; 
namespace SimpleTCPClient 

{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
     } 

     private void browseButton_Click(object sender, RoutedEventArgs e) 
     { 
      OpenFileDialog openFileDialog = new OpenFileDialog(); 
      if (openFileDialog.ShowDialog() == true) 
       fileTextbox.Text = (openFileDialog.FileName); 

     } 

     private void btnSend_Click(object sender, RoutedEventArgs e) 
     { 
      Stream fileStream = File.OpenRead(fileTextbox.Text); 
      // Alocate memory space for the file 
      byte[] fileBuffer = new byte[fileStream.Length]; 
      fileStream.Read(fileBuffer, 0, (int)fileStream.Length); 
      // Open a TCP/IP Connection and send the data 
      TcpClient clientSocket = new TcpClient(ipTextbox.Text, 8080); 
      NetworkStream networkStream = clientSocket.GetStream(); 
      networkStream.Write(fileBuffer, 0, fileBuffer.GetLength(0)); 
      networkStream.Close(); 
     } 
    } 
} 

回答

1

如果lbConnections是一個客戶端控件,你不能從一個後臺線程修改它 - 你必須調用,將做GUI線程上更新的方法。在GUI控件上實際上沒有線程安全性,並且所有禁用Control.CheckForIllegalCrossThreadCalls的功能都會讓您在腳下自拍時變得不那麼明顯。

一般而言,您還有其他問題。例如,您的處理程序線程總是試圖抓取最後一個連接 - 在處理線程嘗試抓取套接字之前,有兩種連接可能發生(並且都會添加到nSockets中) - 這意味着一個套接字永遠不會被抓住一個人抓住兩次。另外,它看起來像你從來沒有實際處理任何套接字對象,甚至不允許它們是GCd,因爲我沒有看到任何從nSockets中移除的代碼。

你確實有兩個很好的選擇 - 要麼傳遞處理線程所需的數據,要麼使用類似隊列的東西,並讓處理線程出列一個套接字並對其進行操作(當然,所有的隊列訪問都必須同步)。無論哪種方式,你應該處理的插座,而不是永遠保持它們。

相關問題