【问题标题】:C# TCP Server to Multi Clients (Unknown number of clients listening)C# TCP 服务器到多客户端(未知数量的客户端监听)
【发布时间】:2015-01-12 18:42:06
【问题描述】:

我正在尝试编写一个由服务器和一些客户端构建的小程序。 服务器将向客户端传输/推送文本消息(客户端不允许发送回服务器,所有客户端都应该从服务器获得相同的文本消息) 我在这里和网上看到了一些关于这个主题的问题,但没有得到我正在寻找的确切解决方案。 大多数解决方案是为每个客户端创建一个线程。但是让我们假设我并不总是知道有多少客户会在某个时间收听。可以是 2,也可以是 30。 我知道有一种方法可以创建一个线程池并让 .NET 处理分配线程,但从来没有一个好的实践,我对线程的了解也没有任何好处。 现在我有一个简单的服务器到客户端程序,它可以按预期工作,但同样,只有一个客户端。 所以这是我的代码:

服务器:

using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows;

namespace NetMessageServerWpf
{
    public partial class MainWindow : Window
    {
        TcpClient client;

        public MainWindow()
        {
            InitializeComponent();
            this.tcpListener = new TcpListener(IPAddress.Any, 3000);
            this.listenThread = new Thread(new ThreadStart(ListenForClients));
            this.listenThread.Start();
        }

        private void btnSend_Click(object sender, RoutedEventArgs e)
        {
            if(client == null || !client.Connected)
                client = this.tcpListener.AcceptTcpClient();
            msg = txtMessage.Text;
            SendTCP(client);
        }

        public TcpListener tcpListener;
        public Thread listenThread;

        private string msg;

        private void ListenForClients()
        {
            this.tcpListener.Start();
        }

        public void SendTCP(TcpClient tcpClient)
        {
            NetworkStream clientStream = tcpClient.GetStream();
            ASCIIEncoding encoder = new ASCIIEncoding();
            byte[] buffer = encoder.GetBytes(this.msg);
            clientStream.Write(buffer, 0, buffer.Length);
            clientStream.Flush();
        }
    }
}

客户:

using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace NetClientSideWpf
{
    class Client : Base
    {

        private string messageString;
        public string MessageString
        {
            get { return messageString; }
            set
            {
                messageString = value;
                OnPropertyChanged("MessageString");
            }
        }


        public Client()
        {
            ConnectToServer();
        }

        public void ConnectToServer()
        {
            TcpClient client = new TcpClient();

            IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 3000);

            client.Connect(serverEndPoint);


            NetworkStream clientStream = client.GetStream();

            Thread ServerThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
            ServerThread.Start(client);


        }

        private void HandleClientComm(object client)
        {
            TcpClient tcpClient = (TcpClient)client;
            NetworkStream clientStream = tcpClient.GetStream();

            byte[] message = new byte[4096];
            int bytesRead;

            while (true)
            {
                bytesRead = 0;

                try
                {
                    bytesRead = clientStream.Read(message, 0, 4096);
                }
                catch
                {
                    break;
                }

                if (bytesRead == 0)
                {
                    break;
                }

                ASCIIEncoding encoder = new ASCIIEncoding();
                MessageString = encoder.GetString(message, 0, bytesRead);
            }
        }
    }
}

任何帮助都可以! :)

【问题讨论】:

    标签: c# multithreading tcp client server


    【解决方案1】:

    我认为首先你应该在你的应用程序开始时启动你的监听器。 然后查看传入连接的间隔(定时器)(TCPListener.Pending http://msdn.microsoft.com/de-de/library/system.net.sockets.tcplistener.pending(v=vs.110).aspx) 如果你得到一个连接,你应该将 TCPClient 保存在一个列表中。 点击按钮将消息发送给您的客户。

    我认为这不是最好的解决方案,但它是一个没有多线程的解决方案 ;-)

    我写了一些示例代码,希望对你有帮助(未经测试):

    public partial class MainWindow : Window
    {
    
        private TcpListener _server;
        private List<TcpClient> _connectedClients;
    
        public MainWindow()
        {
            InitializeComponent();
    
            _server = new TcpListener(IPAddress.Any, 3000);
            _connectedClients = new List<TcpClient>();
            _server.Start();
    
            DispatcherTimer timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromSeconds(1); //every 1 sec!
            timer.Tick += timer_Tick;
            timer.Start();
        }
    
        private void SendMessage(string message)
        {
            ASCIIEncoding encoder = new ASCIIEncoding();
            byte[] buffer = encoder.GetBytes(message);
            foreach (var client in _connectedClients)
            {
                NetworkStream clientStream = client.GetStream();
                clientStream.Write(buffer, 0, buffer.Length);
                clientStream.Flush();
            }
        }
    
    
        void timer_Tick(object sender, EventArgs e)
        {
            Debug.WriteLine("Tick");
            Title = "hello";
    
            if (_server.Pending())
            {
                _connectedClients.Add(_server.AcceptTcpClient());
            }
        }
    
    }
    

    【讨论】:

    • 我已经编辑了我的问题,我忘了提到所有客户都应该收到相同的短信(所以我认为没有必要“列出”他们)。我不介意使用线程,但我怎么能确定我有足够的线程等等。
    • 您必须列出它们。每个连接的客户端都有一个 TcpClient。所以你必须记住所有然后在一个列表中。我不知道 TCPListener 上的属性或方法来向所有客户端发送消息。
    • 好的,我会尝试写一个示例!
    • 似乎工作得很好,所以谢谢你:) 有一件事让我很困扰......每 1 秒检查一次连接,这不是消耗资源吗?这就是你说你认为这不是最好的解决方案的原因吗?
    • 正确!我会使用一个带有while循环的线程并在那里检查传入的连接。但你必须锁定你的客户名单。