简体   繁体   English

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

[英]Server Client send/receive multiple clients

I have to make multiple clients communicate with the server, and the server chooses who to reply to.我必须让多个客户端与服务器通信,服务器选择回复谁。 It is as if the client's only destination to send the message is the server.就好像客户端发送消息的唯一目的地是服务器。 And the server chooses who to talk to.服务器选择与谁交谈。

The point is that I don't know how to make multiple clients first and direct the messages to any of those clients that I want.关键是我不知道如何首先创建多个客户端并将消息定向到我想要的任何客户端。

I just got to do a 1 to 1. Client and server.我只需要做一个 1 对 1 的客户端和服务器。

Also I do not know if I will have to use many threads, since I would need a thread to listen to all the connections of the new clients, another thread to listen to what they send me and thus be able to send.另外我不知道我是否必须使用很多线程,因为我需要一个线程来监听新客户端的所有连接,另一个线程来监听他们发送给我的内容,从而能够发送。

There I leave my code.我留下我的代码。

SERVER服务器

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

CLIENT客户

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

You can use TCP/IP to communicate with server using multiple clients您可以使用 TCP/IP 与使用多个客户端的服务器进行通信

check this question and answers Server Client send/receive simple text检查这个问题和答案服务器客户端发送/接收简单文本

You don't need to deal with threads and tasks since .NET TCP classis takes care of that for you.您不需要处理线程和任务,因为 .NET TCP 类会为您处理这些。

Note that in the TCP listener code you must do it in a while loop in order to keep the listener up and running:请注意,在 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();
}

Do not use any low-level Socket libraries like TcpListener or System.Net.Sockets unless you are trying to learn socket programming or doing a school project.不要使用任何低级 Socket 库,例如TcpListenerSystem.Net.Sockets ,除非您正在尝试学习套接字编程或做一个学校项目。 There are plenty of well-supported .NET libraries for doing client-server communication that handle low level sockets and multi-threading for you so you can focus on your business rules.有大量支持良好的 .NET 库用于进行客户端-服务器通信,为您处理低级套接字和多线程,因此您可以专注于您的业务规则。

Will the final server run on IIS?最终服务器会在 IIS 上运行吗? If yes, look into using SignalR .如果是,请考虑使用SignalR It supports both client and server and has advance user management on the server side so the server can send replies or data to individual clients or whole groups based on custom criteria.它支持客户端和服务器,并在服务器端具有高级用户管理,因此服务器可以根据自定义标准向单个客户端或整个组发送回复或数据。

If you cannot use IIS, try NetCoreServer , It features async client and server and has examples using TCP, UDP, HTTP, and WebSockets.如果您不能使用 IIS,请尝试NetCoreServer ,它具有异步客户端和服务器,并有使用 TCP、UDP、HTTP 和 WebSockets 的示例。

There are multiple other libraries to consider.还有多个其他库需要考虑。 If you do decide to use sockets take a look at the list in this answer .如果您决定使用套接字,请查看此答案中的列表。

Update更新

Since this is for a school project where socket programming is a requirement, you can do the following.由于这是一个需要套接字编程的学校项目,您可以执行以下操作。

Server服务器

  • Use a tread-safe collection like a ConcurrectDictionary to store connected clients使用像ConcurrectDictionary这样的安全集合来存储连接的客户端
  • Each client object would use events to receive data from its client as well as detect a client disconnect每个客户端对象将使用events从其客户端接收数据并检测客户端断开连接
  • The server would subscribe to those events and do whatever it needs when a message is received服务器将订阅这些事件并在收到消息时执行它需要的任何操作
  • When the server does any client operation like sending messages, it needs to lock the operation to avoid deadlocks服务端在做任何客户端操作如发送消息时,需要对操作lock ,避免死锁
  • When a client disconnects, make sure to unsubscribe from any subscriptions for this client to avoid memory leaks当客户端断开连接时,请确保取消订阅此客户端的任何订阅以避免内存泄漏
  • Here is a good example这是一个很好的 例子

Client客户

  • Can use TCPClient or plain Socket and SocketAsyncEventArgs可以使用TCPClient或普通SocketSocketAsyncEventArgs
  • You can look at SocketAsyncEventArgs to check when an operation completes您可以查看SocketAsyncEventArgs以检查操作何时完成
  • You can use async sockets so you do not need to do threads manually您可以使用异步套接字,因此您不需要手动执行线程
  • Here is a good example and here is another这是一个很好的例子,这是另一个

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM