2016-10-22 7 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を無効にすると、足で自分を撃ってもあまり目立たなくなります。

一般に、その他の問題があります。たとえば、ハンドラスレッドは常に最後の接続を取得しようとします。ハンドラスレッドのいずれかがソケットを取得しようとする前に、2つの接続が発生する可能性が非常に高くなります(両方ともnSocketsに追加されます) 1つは2回つかまえられます。さらに、ソケットオブジェクトを実際に処理したり、GCdにすることもできないようです。なぜなら、nSocketからコードを削除するコードは表示されないからです。

実際には、ハンドラスレッドに必要なデータを渡すか、キューのようなものを使用し、ハンドラスレッドがソケットをデキューして操作する(もちろん、すべてのキューアクセスを同期させる必要があります)。いずれにせよ、あなたはソケットを処分し、永遠にそれらを保管しないでください。

関連する問題