2013-11-03 55 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循環() 它接受客戶端後,再次運行while循環,但在

TcpClient client = this.tcpListener.AcceptTcpClient(); 

退出而停止,並顯示在我

this.tcpListener.Start(); 

什麼我做錯了錯誤?

回答

0

通過它的聲音,您試圖運行兩個偵聽器 - 在「AcceptTcpClient」停止的代碼是原始偵聽器:應該沒有其他線程嘗試同時運行tcpListener.Start。首先要做的是添加日誌記錄,包含託管線程ID - 這樣您就可以看到什麼線程在做什麼。您還可以查看調用tcpListener.Start的代碼的堆棧跟蹤以查看來自哪裏,因爲該不應該發生(此時監聽器已在運行)。

作爲設計要點:不建議使用thread-per-client。

+0

如何添加包含託管線程ID的日誌記錄? – Atom97

+0

@Atom trace.writeline與文本中的Thread.CurrentThread.ManagedThreadId應該做 –

0

在ClientComm中創建新窗體時,您將開始一個新的listenThread。

Form1 p = new Form1(); 

如前所述,您只能在端口上偵聽一次,while循環將爲新連接生成線程。 您應該嘗試捕獲acceptTCPClient,例如停止會給你一個例外,你需要趕上。