2016-10-22 5 views
0

TCP 클라이언트를 보내기 버튼을 누를 때마다 TCP 서버가 중지되고이 오류가 발생합니다. 다른 스레드를 소유하고 있기 때문에다른 스레드가 내 개체를 사용하는 이유는 무엇입니까?

호출 스레드가이 개체에 액세스 할 수 없습니다.

디버깅을 시도했지만 문제를 찾을 수 없습니다. 나를 괴롭 히고 TCP/IP와 스레딩을 처음 사용하기 때문에 어떻게하면이 문제를 해결할 수 있을까요? 나는 그것이 어떻게 작동하는지 알지만 예.

listenerThread() 메소드에서이 오류가 발생하여이 오류가 발생합니다. lbConnections 클라이언트 제어 경우

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

, 당신은 배경 스레드에서 수정할 수 없습니다 - 당신이 GUI 스레드에서 업데이트를 할 것입니다 방법을 호출해야합니다. 사실 GUI 컨트롤에는 스레드 안전이 없으므로 Control.CheckForIllegalCrossThreadCalls를 비활성화하면 발을 쏠 때 그다지 명확하지 않게됩니다.

일반적으로 다른 문제가 있습니다. 예를 들어, 처리기 스레드는 항상 마지막 연결을 시도합니다. 처리기 스레드 중 하나가 소켓을 잡으려고하기 전에 두 개의 연결이 발생할 수 있고 (둘 다 nSockets에 추가 될 가능성이 매우 높습니다.) 한 소켓이 결코 잡히지 않습니다 그리고 사람은 두 번 부여 잡았다. 게다가, 실제로 소켓 객체를 처리하지 않았거나 nSocket에서 제거하는 코드가 보이지 않기 때문에 GCD가 될 수 있습니다.

실제로 처리기 스레드에 필요한 데이터를 전달하거나 대기열과 같은 것을 사용하고 처리기 스레드가 하나의 소켓을 대기열에서 제외하고 작업하도록합니다 (물론 모든 대기열 액세스가 동기화되어야 함). 어느 쪽이든 당신은 소켓을 폐기하고 영원히 유지하지 않아야합니다.

관련 문제