2013-11-03 5 views
0
나는 최근에 내가 발견 한 코드를 사용하고 봤는데

멀티 스레드 서버 소켓 예외는

서버가 잘 시작하고 대기 고객을위한 그러나 광산의 서버를 설계하는 멀티 스레드 불공정 한 클라이언트는 난을 연결할 때

Only one usage of each socket address (protocol/network address/port) is normally permitted

코드 :

public partial class Form1 : Form 
{ 
    Server s; 
    public Form1() 
    { 
     InitializeComponent(); 

     s = new Server(this); 
     s.StartTcpServer(); 
    } 
    private void Stop_Btn_Click(object sender, EventArgs e) 
    { 
     s.StopListenForClients(); 
    } 
    public void addButton(int x, int y, String text) 
    { 
     Button btn = new Button(); 
     btn.Size = new Size(50, 50); 
     btn.Location = new Point(x, y); 
     btn.Text = text; 
     btn.Visible = true; 
     this.Controls.Add(btn); 
    } 
} 
class Server 
{ 
    public event EventHandler recvdChanged; 
    private TcpListener tcpListener; 
    private Thread listenThread; 
    private string recvd; 
    Form1 _f1parent; 
    public Server(Form1 par) 
    { 
     _f1parent = par; 
    } 
    public string getsetrecvd 
    { 
     get { return this.recvd; } 
     set 
     { 
      this.recvd = value; 
      if (this.recvdChanged != null) 
       this.recvdChanged(this, new EventArgs()); 
     } 
    } 
    public void StartTcpServer() 
    { 
     this.tcpListener = new TcpListener(IPAddress.Any, 8000); 
     this.listenThread = new Thread(new ThreadStart(ListenForClients)); 
     this.listenThread.Start(); 
    } 
    static Boolean b = false; 
    private void ListenForClients() 
    { 
     //where are recive the error 
     this.tcpListener.Start(); 

     while (true) 
     { 
      //blocks until a client has connected to the server 
      TcpClient client = this.tcpListener.AcceptTcpClient(); 
      if (client.Connected) 
      { 
       b = true; 
      // MessageBox.Show(client.Client.RemoteEndPoint + " Has Connected."); 
      } 

      //create a thread to handle communication 
      //with connected client 
      Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm)); 
      clientThread.Start(client); 
      b = false; 
     } 
    } 
    public void StopListenForClients() 
    { 
     tcpListener.Stop(); 
    } 
    private void HandleClientComm(object client) 
    { 
     TcpClient tcpClient = (TcpClient)client; 
     NetworkStream clientStream = tcpClient.GetStream(); 

     byte[] message = new byte[4096]; 
     int bytesRead; 
     Form1 p = new Form1(); 
     while (true) 
     { 
      bytesRead = 0; 

      try 
      { 
       //blocks until a client sends a message 
       bytesRead = clientStream.Read(message, 0, 4096); 

      } 
      catch 
      { 
       //a socket error has occured 
       break; 
      } 

      if (bytesRead == 0) 
      { 
       //the client has disconnected from the server 
       break; 
      } 

      //message has successfully been received 
      ASCIIEncoding encoder = new ASCIIEncoding(); 
      getsetrecvd = encoder.GetString(message, 0, bytesRead); 
      if (recvd != "e") 
      { 
      } 
      else 
      { 
       break; 
      } 
     } 

     tcpClient.Close(); 
    } 
} 

내가 프로그램을 디버깅하고 ListenForClients에서 while 루프를 (실행)fallowing 오류가하고 클라이언트를 받아 후에 다시 while 루프를 실행하지만

TcpClient client = this.tcpListener.AcceptTcpClient(); 

그동안를 종료에 정지하고 나에게 내가 잘못 뭐하는 거지

this.tcpListener.Start(); 

에서 오류를 보여줍니다?

답변

0

두 개의 리스너를 실행하려고합니다. "AcceptTcpClient"에서 중지 된 코드가 원래 수신기입니다. tcpListener.Start를 실행하려고하는 다른 스레드가 없어야합니다. 가장 먼저 할 일은 에 관리되는 스레드 ID이 포함 된 로깅을 추가하는 것입니다. 그러면 어떤 스레드가 무엇을하는지 볼 수 있습니다. 이 일어나서는 안되기 때문에 tcpListener.Start를 호출하는 코드의 스택 추적을 살펴볼 수도 있습니다. (이 시점에서 수신기가 이미 실행 중입니다).

디자인 포인트 : 클라이언트 당 스레드 수는 권장되지 않습니다.

+0

관리되는 스레드 ID가 포함 된 로깅을 어떻게 추가합니까? – Atom97

+0

텍스트에서 Thread.CurrentThread.ManagedThreadId를 사용하여 @Atom trace.writeline이 수행해야하는 작업 –

0

ClientComm에서 새 양식을 만들 때 새 listenThread를 시작합니다.

Form1 p = new Form1(); 

앞에서 설명한 것처럼 포트에서 한 번만들을 수 있으며 while 루프는 새로운 연결을위한 스레드를 생성합니다. 예를 들어 acceptTCPClient를 잡아야합니다. 정지는 당신이 붙잡아 야 할 예외를 줄 것이다.