服务器客户端发送/接收多个客户端

Posted

技术标签:

【中文标题】服务器客户端发送/接收多个客户端【英文标题】:Server Client send/receive multiple clients 【发布时间】:2021-12-04 01:30:05 【问题描述】:

我必须让多个客户端与服务器通信,服务器选择回复谁。就好像客户端发送消息的唯一目的地是服务器。 服务器选择与谁交谈。

关键是我不知道如何首先创建多个客户端并将消息定向到我想要的任何客户端。

我只需要做一对一的客户端和服务器。

我也不知道我是否必须使用很多线程,因为我需要一个线程来监听新客户端的所有连接,另一个线程来监听他们发送给我的内容,从而能够发送。

我留下我的代码。

对不起我的英语。使用谷歌翻译。

西班牙语: Tengo que hacer que varios clientes se comuniquen con el servidor, y el servidor elige a quién responder。 Es como si el único destino del cliente para enviar el mensaje fuera el servidor。 Y el servidor elige con quién hablar。

El punto es que no sé cómo hacer varios clientes primeo y dirigir los mensajes a cualquiera de esos clientes que quiero。

Solo tengo que hacer un 1 a 1. Cliente y servidor。

Además no sé si tenré que usar muchos hilos, ya que necesitaría un hilo para escuchar todas las conexiones de los nuevos clientes, otro hilo para escuchar lo que me envían y así poder enviar。

Ahí les dejo mi código.

服务器/服务器

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

namespace Servidor_Chat

    class Server
    
        IPAddress ipAddr;
        IPEndPoint endPoint;
        Socket s_Server;
        Socket s_Client;
        public Server()
        
            ipAddr = IPAddress.Any;
            endPoint = new IPEndPoint(ipAddr, 1234);
            s_Server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            s_Server.Bind(endPoint);
            s_Server.Listen(1);
         

        public void Start()
        
            Console.WriteLine("Esperando clientes...");
            s_Client = s_Server.Accept();
            Console.WriteLine("Un cliente se ha conectado.");
            IPEndPoint clientep = (IPEndPoint)s_Client.RemoteEndPoint;
            Console.WriteLine("Conectado con 0 en el puerto 1", clientep.Address, clientep.Port);
        

        public void Send(string msg)
        
            string texto = "";
            byte[] textoAEnviar;
            texto = msg;
            textoAEnviar = Encoding.Default.GetBytes(texto);
            s_Client.Send(textoAEnviar, 0, textoAEnviar.Length, 0);
         

        public void Receive()
        
            while (true)
            
                Thread.Sleep(500);
                byte[] ByRec;
                string textoRecibido = "";
                ByRec = new byte[255];
                int a = s_Client.Receive(ByRec, 0, ByRec.Length, 0);
                Array.Resize(ref ByRec, a);
                textoRecibido = Encoding.Default.GetString(ByRec);
                Console.WriteLine("Client: " + textoRecibido);
                Console.Out.Flush();
            
        
     

    class Program
    
        static void Main(string[] args)
        
            Thread t;
            Server s = new Server();
            s.Start();
            t = new Thread(new ThreadStart(s.Receive));
            t.Start();
            while (true)
            
                s.Send(Console.ReadLine());
             

            Console.WriteLine("Presione cualquier tecla para terminar");
            Console.ReadLine();
        
    

客户

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

namespace Cliente_Chat

    class Program
    
        class Client
        
            IPAddress ipAddr;
            IPEndPoint endPoint;
            Socket s_Client;
            public Client()
            
                ipAddr = IPAddress.Parse("127.0.0.1");
                endPoint = new IPEndPoint(ipAddr, 1234);
                s_Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
             

            public void Start()
            
                try
                
                    s_Client.Connect(endPoint);
                    Console.WriteLine("Conectado con exito");
                
                catch (SocketException e)
                
                    Console.WriteLine("No se pudo conectar al servidor");
                    Console.WriteLine(e.ToString());
                    return;
                
             

            public void Send(string msg)
            
                string texto = "";
                byte[] textoAEnviar;
                texto = msg;
                textoAEnviar = Encoding.Default.GetBytes(texto);
                s_Client.Send(textoAEnviar, 0, textoAEnviar.Length, 0);
             

            public void Receive()
            
                while (true)
                
                    Thread.Sleep(500);
                    byte[] ByRec;
                    string textoRecibido = "";
                    ByRec = new byte[255];
                    int a = s_Client.Receive(ByRec, 0, ByRec.Length, 0);
                    Array.Resize(ref ByRec, a);
                    textoRecibido = Encoding.Default.GetString(ByRec);
                    Console.WriteLine("Server: " + textoRecibido);
                    Console.Out.Flush();
                
            
         

        static void Main(string[] args)
        
            Thread t;
            Client c = new Client();
            c.Start();
            t = new Thread(new ThreadStart(c.Receive));
            t.Start();
            while (true)
            
                c.Send(Console.ReadLine());
             

            Console.WriteLine("Presione cualquier tecla para terminar");
            Console.ReadLine();
        
    

【问题讨论】:

您将能够在网络中找到多个客户端服务器应用程序示例。 根据您的要求,有多个库和包可以用最少的低级代码完成您正在做的事情。如果您将 IIS 用于服务器,您可以将 SignalR 用于服务器和客户端,只关注您的业务规则。图书馆会处理剩下的。 如果你不能使用 IIS 或者不想要 websockets,你可以使用github.com/chronoxor/NetCoreServer。它支持客户端和服务器,并在后台执行所有线程,因此您可以专注于业务逻辑。 【参考方案1】:

您可以使用 TCP/IP 与使用多个客户端的服务器进行通信

检查这个问题和答案Server Client send/receive simple text

您不需要处理线程和任务,因为 .NET TCP 类会为您处理这些。

请注意,在 TCP 侦听器代码中,您必须在 while 循环中执行此操作,以保持侦听器正常运行:

 static void Main(string[] args)

    //---listen at the specified IP and port no.---
    IPAddress localAdd = IPAddress.Parse(SERVER_IP);
    TcpListener listener = new TcpListener(localAdd, PORT_NO);
    Console.WriteLine("Listening...");
    listener.Start();
    while (true)
    
        //---incoming client connected---
        TcpClient client = listener.AcceptTcpClient();

        //---get the incoming data through a network stream---
        NetworkStream nwStream = client.GetStream();
        byte[] buffer = new byte[client.ReceiveBufferSize];

        //---read incoming stream---
        int bytesRead = nwStream.Read(buffer, 0, client.ReceiveBufferSize);

        //---convert the data received into a string---
        string dataReceived = Encoding.ASCII.GetString(buffer, 0, bytesRead);
        Console.WriteLine("Received : " + dataReceived);

        //---write back the text to the client---
        Console.WriteLine("Sending back : " + dataReceived);
        nwStream.Write(buffer, 0, bytesRead);
        client.Close();
    
    listener.Stop();
    Console.ReadLine();

【讨论】:

当然,我会理解这一点,从我尝试的问题来看,如果我将其保留为这样的线程,我不能做任何其他事情,对吧?因为,例如,如果我想回答所有与我交谈的客户的消息,我不能因为有一段时间,所以我不必使用线程或任务?对不起,无知。这是一个学校项目。 Console.WriteLine("发回:" + dataReceived);您可以将此代码替换为您想要回复发件人或执行任何事件的任何内容 当然,和每个人都这么说话,但是如果你想和一个特定的人说话,你是否必须保存套接字之类的东西? 是的,您必须为服务器上的每个客户端保存一个套接字或TcpClient。因此,您将拥有一个客户集合,并从该集合中选择向谁发送数据。 @Hades 如果回答对你有帮助请采纳【参考方案2】:

不要使用任何低级 Socket 库,例如 TcpListenerSystem.Net.Sockets,除非您正在尝试学习套接字编程或做一个学校项目。有大量支持良好的 .NET 库用于进行客户端-服务器通信,为您处理低级套接字和多线程,因此您可以专注于您的业务规则。

最终的服务器会在 IIS 上运行吗?如果是,请考虑使用SignalR。它同时支持客户端和服务器,并且在服务器端具有高级用户管理,因此服务器可以根据自定义标准向单个客户端或整个组发送回复或数据。

如果你不能使用 IIS,试试NetCoreServer,它具有异步客户端和服务器,并有使用 TCP、UDP、HTTP 和 WebSockets 的示例。

还有多个其他库需要考虑。如果您决定使用套接字,请查看answer 中的列表。

更新

由于这是一个需要套接字编程的学校项目,您可以执行以下操作。

服务器

使用像 ConcurrectDictionary 这样的安全集合来存储连接的客户端 每个客户端对象都将使用events 从其客户端接收数据并检测客户端断开连接 服务器将订阅这些事件并在收到消息时执行它需要的任何操作 服务器在做任何客户端操作如发送消息时,需要lock该操作避免死锁 当客户端断开连接时,请确保取消订阅此客户端的任何订阅以避免内存泄漏 这是一个很好的example

客户

可以使用TCPClient或普通SocketSocketAsyncEventArgs 您可以查看SocketAsyncEventArgs 以检查操作何时完成 您可以使用异步套接字,因此您无需手动执行线程 这是一个很好的example,这是another

【讨论】:

如果是学校项目理解操作,问题有点不同,服务器同时充当客户端,唯一不同的是服务器接收到所有客户端,可以分别响应每一个,客户端显然只能私下与服务端对话。 我明白了。看起来您正在尝试创建一个聊天室,其中聊天室是服务器,客户端是客户端。服务器需要保留已连接客户端的列表,我建议ConcurrentDictionary 在连接/断开连接时添加或删除客户端。当服务器需要发送一些东西时,它可以使用您拥有的任何业务规则遍历客户端列表发送给每个客户端。这需要多线程,但您可以使用Eventslocks 避免细节。 ***.com/questions/69653295/… 对我来说,这是我的错误。我不知道放置 Console.WriteLine 并没有显示它发生在我身上。现在它显示了。一定是在电脑上呆了这么多小时,我什至不知道该怎么办。如果我在将其传递给 Windows 窗体时遇到问题怎么办。 es.***.com/questions/491989/… 你知道这是什么吗?我还尝试将示例代码传递给 windows 窗体,同样的事情也发生在我身上。在这种情况下,它是有问题的客户。

以上是关于服务器客户端发送/接收多个客户端的主要内容,如果未能解决你的问题,请参考以下文章

当有多个服务器广播时,客户端如何接收多个广播消息?

Java Socket 通信之多线程

从服务器接收多个 sendto()

服务器和客户端正在发送多个对象[重复]

多播组客户端不从服务器接收消息

异步接收来自服务器的消息