簡體   English   中英

服務器客戶端發送/接收多個客戶端

[英]Server Client send/receive multiple clients

我必須讓多個客戶端與服務器通信,服務器選擇回復誰。 就好像客戶端發送消息的唯一目的地是服務器。 服務器選擇與誰交談。

關鍵是我不知道如何首先創建多個客戶端並將消息定向到我想要的任何客戶端。

我只需要做一個 1 對 1 的客戶端和服務器。

另外我不知道我是否必須使用很多線程,因為我需要一個線程來監聽新客戶端的所有連接,另一個線程來監聽他們發送給我的內容,從而能夠發送。

我留下我的代碼。

服務器

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

您可以使用 TCP/IP 與使用多個客戶端的服務器進行通信

檢查這個問題和答案服務器客戶端發送/接收簡單文本

您不需要處理線程和任務,因為 .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();
}

不要使用任何低級 Socket 庫,例如TcpListenerSystem.Net.Sockets ,除非您正在嘗試學習套接字編程或做一個學校項目。 有大量支持良好的 .NET 庫用於進行客戶端-服務器通信,為您處理低級套接字和多線程,因此您可以專注於您的業務規則。

最終服務器會在 IIS 上運行嗎? 如果是,請考慮使用SignalR 它支持客戶端和服務器,並在服務器端具有高級用戶管理,因此服務器可以根據自定義標准向單個客戶端或整個組發送回復或數據。

如果您不能使用 IIS,請嘗試NetCoreServer ,它具有異步客戶端和服務器,並有使用 TCP、UDP、HTTP 和 WebSockets 的示例。

還有多個其他庫需要考慮。 如果您決定使用套接字,請查看此答案中的列表。

更新

由於這是一個需要套接字編程的學校項目,您可以執行以下操作。

服務器

  • 使用像ConcurrectDictionary這樣的安全集合來存儲連接的客戶端
  • 每個客戶端對象將使用events從其客戶端接收數據並檢測客戶端斷開連接
  • 服務器將訂閱這些事件並在收到消息時執行它需要的任何操作
  • 服務端在做任何客戶端操作如發送消息時,需要對操作lock ,避免死鎖
  • 當客戶端斷開連接時,請確保取消訂閱此客戶端的任何訂閱以避免內存泄漏
  • 這是一個很好的 例子

客戶

  • 可以使用TCPClient或普通SocketSocketAsyncEventArgs
  • 您可以查看SocketAsyncEventArgs以檢查操作何時完成
  • 您可以使用異步套接字,因此您不需要手動執行線程
  • 這是一個很好的例子,這是另一個

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM