【问题标题】:C# Socket Multithreading LambdaC# Socket 多线程 Lambda
【发布时间】:2017-04-29 12:45:01
【问题描述】:

我有以下 C# 代码:

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();
        }
    }
}
  • run 不应该在循环中创建新线程吗?
  • 如果第一个问题不成立,并且 lambda 表达式已经创建了新线程,那么在什么时候创建新线程?决定它的逻辑在哪里?

【问题讨论】:

    标签: c# multithreading sockets lambda


    【解决方案1】:

    new Thread( 将创建新线程。 lambda 在线程上执行。运行应该处于循环中。因为它会创建很多线程。

    and the lambda expression already creates new thread,不,它会被用作线程方法。


    唯一的问题是,你没有对线程的引用,所以你不能等到它被终止。

    您还在 while 循环中使用了 bool running。你最好使用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

    服务器的问题在于,您不负责连接多少客户端。


    一些伪代码如何设置您的 tcp-server 并为每个客户端运行线程。

    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();
        }
    }
    

    【讨论】:

    • 感谢您的回答。问题是,对于每个新的套接字连接,都应该有一个新线程,对吧?这段代码 sn-p 只创建一个线程,所以这个服务器不是多线程的?每个新连接都应该有一个线程吧?
    • 是的,您应该为每个连接的套接字创建一个新线程或使用异步套接字。每个套接字的线程要快得多(大约 1.5 倍),但可扩展性不是很好。每个客户端都会消耗一个线程。
    • 对,你只接受客户端套接字,它们没有被处理。所以你的听众在一个单独的线程上,你的客户没有得到处理。因此,您需要创建一个单独的类,该类将为每个客户端生成一个线程。您应该将套接字传递给每个客户端类的构造函数。你想要的循环,不会解决它。因为你应该只听一个线程。
    • 当然可以,但您可能不想阻止您的 gui 线程。
    • 第二个会等到第一个被接受,监听线程返回Accept模式。所以,它会等待。 (只是创建一个新线程并返回接受,不需要很长时间) ....如果有很多客户端正在连接,您可以使用@987654321的积压参数设置accept-waiters的限制@
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-18
    • 1970-01-01
    • 2014-10-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多