2016-12-14 55 views
2

我有下面的C#代碼:C#SOCKET多線程拉姆達

using System.Collections.Generic; 
 
using System.Net; 
 
using System.Net.Sockets; 
 
using System.Threading; 
 

 
namespace CTCServer 
 
{ 
 
    class Server 
 
    { 
 
     //Stores the IP Adress the server listens on 
 
     private IPAddress ip; 
 

 
     //Stores the port the server listens on 
 
     private int port; 
 

 
     //Stores the counter of connected clients. *Note* The counter only gets increased, it acts as "id" 
 
     private int clientCount = 0; 
 

 
     //Defines if the server is running. When chaning to false the server will stop and disconnect all clients. 
 
     private bool running = true; 
 

 
     //Stores all connected clients. 
 
     public List<Client> clients = new List<Client>(); 
 

 
     //Event to pass recived data to the main class 
 
     public delegate void GotDataFromCTCHandler(object sender, string msg); 
 
     public event GotDataFromCTCHandler GotDataFromCTC; 
 

 
     //Constructor for Server. If autoStart is true, the server will automaticly start listening. 
 
     public Server(IPAddress ip, int port, bool autoStart = false) 
 
     { 
 
      this.ip = ip; 
 
      this.port = port; 
 

 
      if (autoStart) 
 
       this.Run(); 
 
     } 
 

 
     //Starts the server. 
 
     public void Run() 
 
     { 
 
      //Run in new thread. Otherwise the whole application would be blocked 
 
      new Thread(() => 
 
      { 
 
       //Init TcpListener 
 
       TcpListener listener = new TcpListener(this.ip, this.port); 
 

 
       //Start listener 
 
       listener.Start(); 
 

 
       //While the server should run 
 
       while (running) 
 
       { 
 
        //Check if someone wants to connect 
 
        if (listener.Pending()) 
 
        { 
 
         //Client connection incoming. Accept, setup data incoming event and add to client list 
 
         Client client = new Client(listener.AcceptTcpClient(), this.clientCount); 
 

 
         //Declare event 
 
         client.internalGotDataFromCTC += GotDataFromClient; 
 

 
         //Add to list 
 
         clients.Add(client); 
 

 
         //Increase client count 
 
         this.clientCount++; 
 
        } 
 
        else 
 
        { 
 
         //No new connections. Sleep a little to prevent CPU from going to 100% 
 
         Thread.Sleep(100); 
 
        } 
 
       } 
 

 
       //When we land here running were set to false or another problem occured. Stop server and disconnect all. 
 
       Stop(); 
 
      }).Start(); //Start thread. Lambda \(o.o)/ 
 
     } 
 

 
     //Fires event for the user 
 
     private void GotDataFromClient(object sender, string data) 
 
     { 
 
      //Data gets passed to parent class 
 
      GotDataFromCTC(sender, data); 
 
     } 
 

 
     //Send string "data" to all clients in list "clients" 
 
     public void SendToAll(string data) 
 
     { 
 
      //Call send method on every client. Lambda \(o.o)/ 
 
      this.clients.ForEach(client => client.Send(data)); 
 
     } 
 

 
     //Stop server 
 
     public void Stop() 
 
     { 
 
      //Exit listening loop 
 
      this.running = false; 
 

 
      //Disconnect every client in list "client". Lambda \(o.o)/ 
 
      this.clients.ForEach(client => client.Close()); 
 

 
      //Clear clients. 
 
      this.clients.Clear(); 
 
     } 
 
    } 
 
}

  • 應該運行不是在一個循環中創建新的線程?
  • 如果第一個問題不是真的,並且lambda表達式已經創建了新的線程,那麼在哪個時候創建​​了新的線程?決定它的邏輯在哪裏?

謝謝先進。

回答

3

new Thread(將創建新的線程。 lambda在線程上執行。運行應而不是處於循環中。因爲它會創建很多線程。

and the lambda expression already creates new thread,no它將被用作線程方法。


唯一的問題是,你沒有對線程的引用,所以你不能等到它終止。

另外,您正在使用bool running作爲while循環。你最好使用ManualResetEvent


我用這個作爲標準的線程設置:

// signal for terminating the thread. 
private ManualResetEvent _terminating = new ManualResetEvent(false); 
private Thread _thread; 

public void Start() 
{ 
    ManualResetEvent threadStarted = new ManualResetEvent(false); 

    _thread = new Thread(() => 
    { 
     threadStarted.Set(); 

     while(!_terminating.WaitOne(0)) 
     { 
      // do your thing here. 
     } 
    }); 

    _thread.Start(); 
    threadStarted.WaitOne(); 
} 

public void Dispose() 
{ 
    _terminating.Set(); 
    _thread.Join(); 
} 
這裏

一個備註是:如果你使用線程客戶端或異步插座。

  • 線程客戶端:客戶端數量< = 10
  • 異步套接字:客戶端計數> 10

與服務器的問題是,你不負責的許多客戶是如何連接的。


一些僞代碼如何設置你的tcp服務器併爲每個客戶端運行線程。

public class Server 
{ 

    // signal for terminating the thread. 
    private ManualResetEvent _terminating = new ManualResetEvent(false); 

    private List<ClientHandler> _clients = new List<ClientHandler>(); 

    public void Start() 
    { 
     ManualResetEvent threadStarted = new ManualResetEvent(false); 

     _thread = new Thread(() => 
     { 
      threadStarted.Set(); 

      // create listener..... 

      while(!_terminating.WaitOne(0)) 
      { 
       // do your thing here. 

       // accept socket 
       var socket = _listenerSocket.Accept(); 

       ClientHandler handler = new ClientHandler(socket); 
       _clients.Add(handler); 

      } 
     }); 

     _thread.Start(); 
     threadStarted.WaitOne(); 
    } 

    public void Dispose() 
    { 
     _terminating.Set(); 
     _thread.Join(); 
    } 

} 


public class ClientHandler 
{ 
    // signal for terminating the thread. 
    private ManualResetEvent _terminating = new ManualResetEvent(false); 

    public ClientHandler(Socket socket) 
    { 
     ManualResetEvent threadStarted = new ManualResetEvent(false); 

     _thread = new Thread(() => 
     { 
      threadStarted.Set(); 

      while(!_terminating.WaitOne(0)) 
      { 
       // do your thing here. 

       // accept socket 
       var bytesReaded = socket.Read(.....); 
       // handle data.... 
      } 
     }); 

     _thread.Start(); 
     threadStarted.WaitOne(); 
    } 

    public void Dispose() 
    { 
     _terminating.Set(); 
     _thread.Join(); 
    } 
} 
+0

感謝您的回答。問題是,對於每個新的套接字連接都有一個新的線程是正確的?這段代碼只創建一個線程,所以這個服務器不是多線程的?每個新連接都應該有一個線程? – redigaffi

+0

是的,您應該爲每個連接的套接字創建一個新線程或**使用異步套接字**。每個套接字的線程速度更快(約1.5倍),但不具有可伸縮性。它會消耗每個客戶端的線程。 –

+0

然後,我的代碼片段只會創建1個線程嗎?所以它不是一個多線程套接字服務器,不能接受多個連接權限?我怎麼能改變它,所以它接受多個連接 – redigaffi