One: Basic Socket usage

TCP USES

The service side

public static void Proccess()
{
    int port = 2018;
    string host = "127.0.0.1";

    IPAddress ip = IPAddress.Parse(host);
    IPEndPoint ipe = new IPEndPoint(ip, port);

    Socket sSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    sSocket.Bind(ipe);
    sSocket.Listen(0);
    Console.WriteLine("Listening is on. Please wait.");

    // Receive a message to accept a socket link
    Socket serverSocket = sSocket.Accept();
    Console.WriteLine("Connection established...");
    while (true)
    {
        string recStr = "";
        byte[] recByte = new byte[4096];
        int bytes = serverSocket.Receive(recByte, recByte.Length, 0);
        recStr += Encoding.ASCII.GetString(recByte, 0, bytes);
        Console.WriteLine("Server side gets information :{0}", recStr);

        if (recStr.Equals("stop"))
        {
            serverSocket.Close();// Close the socket object
            Console.WriteLine("Close links...");
            break;
        }

        // Send the message back
        Console.WriteLine("Please enter a reply message...");
        string sendStr = Console.ReadLine(); //"send to client :hello world";
        byte[] sendByte = Encoding.ASCII.GetBytes(sendStr);
        serverSocket.Send(sendByte, sendByte.Length, 0);
    }
    sSocket.Close();// Disable server listening
}
Copy the code

The client

static void Main(string[] args)
{
    try
    {
        Console.WriteLine("Start a Socket client link"); 
        int port = 2018;
        string host = "127.0.0.1";// Server IP address
        IPAddress ip = IPAddress.Parse(host);
        IPEndPoint ipe = new IPEndPoint(ip, port); 
        Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        clientSocket.Connect(ipe); // Open the link, the link is long;
        while (true)
        {
            Console.WriteLine("Please enter the information sent to the server:");
            string sendStr = Console.ReadLine();
            if (sendStr == "exit")
                break;

            byte[] sendBytes = Encoding.ASCII.GetBytes(sendStr);
            clientSocket.Send(sendBytes);

            //receive message
            string recStr = "";
            byte[] recBytes = new byte[4096];
            // Monitor incoming messages;
            int bytes = clientSocket.Receive(recBytes, recBytes.Length, 0);
            recStr += Encoding.ASCII.GetString(recBytes, 0, bytes);
            Console.WriteLine($" The server returns:{recStr}");
        }
        clientSocket.Close();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
    Console.Read();
}
Copy the code

The use of UDP

The service side

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace UDP_Server
{
    class Program
    {
        static Socket server;
        static void Main(string[] args)
        {
            server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            server.Bind(new IPEndPoint(IPAddress.Parse("169.254.202.67"), 6001));// Bind port number and IP
            Console.WriteLine("The server is enabled.");
            Thread t = new Thread(ReciveMsg);// Start the receiving thread
            t.Start();
            Thread t2 = new Thread(sendMsg);// Start the sending thread
            t2.Start();


        }
        /// <summary>
        ///Sends a datagram to the port of the host with a specific IP address
        /// </summary>
        static void sendMsg()
        {
            EndPoint point = new IPEndPoint(IPAddress.Parse("169.254.202.67"), 6000);
            while (true)
            {
                stringmsg = Console.ReadLine(); server.SendTo(Encoding.UTF8.GetBytes(msg), point); }}/// <summary>
        ///Receive datagrams sent to the port number corresponding to the local IP
        /// </summary>
        static void ReciveMsg()
        {
            while (true)
            {
                EndPoint point = new IPEndPoint(IPAddress.Any, 0);// Store the sender's IP address and port number
                byte[] buffer = new byte[1024];
                int length = server.ReceiveFrom(buffer, ref point);// Receive datagrams
                string message = Encoding.UTF8.GetString(buffer,0,length); Console.WriteLine(point.ToString()+ message); }}}}Copy the code

The client

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace UDP_client
{
    class Program
    {
        static Socket client;
        static void Main(string[] args)
        {
            client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            client.Bind(new IPEndPoint(IPAddress.Parse("169.254.202.67"), 6000));
            Thread t = new Thread(sendMsg);
            t.Start();
            Thread t2 = new Thread(ReciveMsg);
            t2.Start();
            Console.WriteLine("Client is open");
        }
        /// <summary>
        ///Sends a datagram to the port of the host with a specific IP address
        /// </summary>
        static void sendMsg()
        {
            EndPoint point = new IPEndPoint(IPAddress.Parse("169.254.202.67"), 6001);
            while(true) {stringmsg = Console.ReadLine(); client.SendTo(Encoding.UTF8.GetBytes(msg), point); }}/// <summary>
        ///Receive datagrams sent to the port number corresponding to the local IP
        /// </summary>
        static void ReciveMsg()
        {
            while (true)
            {
                EndPoint point = new IPEndPoint(IPAddress.Any, 0);// Store the sender's IP address and port number
                byte[] buffer = new byte[1024];
                int length = client.ReceiveFrom(buffer, ref point);// Receive datagrams
                string message = Encoding.UTF8.GetString(buffer, 0, length); Console.WriteLine(point.ToString() + message); }}}}Copy the code

Two: Use of SuperSocket

Supersocket. Engine SuperSoket

  1. Session: Each user connection is a Session
  2. AppServer: indicates the Socket server instance
  3. Commands: The set of Commands that a client sends messages to a server

Add the following configuration to the configuration file

<? xml version="1.0" encoding="utf-8"? > <configuration> <configSections> <section name="superSocket" type="SuperSocket.SocketEngine.Configuration.SocketServiceConfig, SuperSocket.SocketEngine"/>
  </configSections>
  <superSocket>
    <servers>
      <server name="ChatSocket" textEncoding="gb2312"
              serverType="XT.SocketService.AppServer.ChatServer,XT.SocketService"
              ip="Any" port="2020"
              maxConnectionNumber="100"> </server> <! -- Multiple servers can be configured --> </ Servers > </superSocket> <startup> <supportedRuntime version="v4.0" sku=". NETFramework, Version = v4.5. "" />
    </startup>
</configuration>
Copy the code

Example Create a ChatServer service

[AuthorisizeFilter]
public class ChatServer:AppServer<ChatSession>
{
    protected override bool Setup(IRootConfig rootConfig, IServerConfig config)
    {
        Console.WriteLine("Ready to read configuration file...");
        return base.Setup(rootConfig, config);
    }

    protected override void OnStarted()
    {
        Console.WriteLine("Chat service started...");
        base.OnStarted();
    }

    protected override void OnStopped()
    {
        Console.WriteLine("Chat service stopped...");
        base.OnStopped();
    }

    /// <summary>
    ///A new connection
    /// </summary>
    /// <param name="session"></param>
    protected override void OnNewSessionConnected(ChatSession session)
    {
        Console.WriteLine($" new connections added to Chat:{session.LocalEndPoint.Address.ToString()}");
        base.OnNewSessionConnected(session); }}Copy the code
class AuthorisizeFilterAttribute : CommandFilterAttribute
{
    public override void OnCommandExecuting(CommandExecutingContext commandContext)
    {
        ChatSession session = (ChatSession)commandContext.Session;
        string command = commandContext.CurrentCommand.Name;
        if(! session.IsLogin) {if(! command.Equals("Check"))
            {
                session.Send("Please log in first and then operate...");
                commandContext.Cancel = true;// Don't go any further;
            }
            else
            { 
                ///.}}else if (!session.IsOnLine)
        {
            session.LastHbTime = DateTime.Now;
        } 
    }
    public override void OnCommandExecuted(CommandExecutingContext commandContext)
    {
        //throw new NotImplementedException();}}Copy the code

Create a Session service

/// <summary>
///Represents user connection
/// </summary>
//[AuthorisizeFilter]
public class ChatSession : AppSession<ChatSession>
{
    public string Id { get; set; }

    public string PassWord { get; set; }

    public bool IsLogin { get; set; }

    public DateTime LoginTime { get; set; }

    public DateTime LastHbTime { get; set; }

    public bool IsOnline
    { 
        get
        {
            return this.LastHbTime.AddSeconds(10) > DateTime.Now; }}/// <summary>
    ///Message is sent
    /// </summary>
    /// <param name="message"></param>
    public override void Send(string message)
    {
        Console.WriteLine($" ready to send to{this.Id}:{message}");
        base.Send(message.Format());
    }

    protected override void OnSessionStarted()
    {
        this.Send("Welcome to SuperSocket Chat Server");
    }

    protected override void OnInit()
    {
        this.Charset = Encoding.GetEncoding("gb2312");
        base.OnInit();
    }

    protected override void HandleUnknownRequest(StringRequestInfo requestInfo)
    {
        Console.WriteLine("Received orders :" + requestInfo.Key.ToString());
        this.Send("I don't know what to do with it." + requestInfo.Key.ToString() + "Command");
    }

    /// <summary>
    ///Abnormal capture
    /// </summary>
    /// <param name="e"></param>
    protected override void HandleException(Exception e)
    {
        this.Send($"\n\r{ e.Message}");
        //base.HandleException(e);
    }

    /// <summary>
    ///Connection is closed
    /// </summary>
    /// <param name="reason"></param>
    protected override void OnSessionClosed(CloseReason reason)
    {
        Console.WriteLine("Link closed...");
        base.OnSessionClosed(reason); }}Copy the code

The client sends message Commands Check 1 123456 Check indicates the class name, 1 indicates session.id (session ID), 1 indicates session.PassWord (session PassWord)

public class Check : CommandBase<ChatSession.StringRequestInfo>
{
    public override void ExecuteCommand(ChatSession session, StringRequestInfo requestInfo)
    {
        if(requestInfo.Parameters ! =null && requestInfo.Parameters.Length == 2)
        {
            ChatSession oldSession = session.AppServer.GetAllSessions().FirstOrDefault(a => requestInfo.Parameters[0].Equals(a.Id));
            if(oldSession ! =null) // said that a user had logged in with this Id before
            {
                oldSession.Send("Your account has been logged in elsewhere. You have been kicked off.");
                oldSession.Close();
            }

            #regionThis is where you can connect to the database for data validation and login
            ///---------------------
            #endregion
            session.Id = requestInfo.Parameters[0];
            session.PassWord = requestInfo.Parameters[1];
            session.IsLogin = true;
            session.LoginTime = DateTime.Now;

            session.Send("Login successful");

            { // Get the offline message of the current logged-in user
                ChatDataManager.SendLogin(session.Id, c =>
                { 
                    session.Send($"{c.FromId}Send you a message:{c.Message} {c.Id}"); }); }}else
        {
            session.Send("Parameter error"); }}}Copy the code

Classes related to offline message stores

public class ChatDataManager
{
    /// <summary>
    ///Key is the user ID
    ///List All messages for the user
    /// </summary>
    private static Dictionary<string.List<ChatModel>> Dictionary = new Dictionary<string, List<ChatModel>>();

    public static void Add(string userId, ChatModel model)
    {
        if (Dictionary.ContainsKey(userId))
        {
            Dictionary[userId].Add(model);
        }
        else
        {
            Dictionary[userId] = newList<ChatModel>() { model }; }}public static void Remove(string userId, string modelId)
    {
        if (Dictionary.ContainsKey(userId))
        {
            Dictionary[userId] = Dictionary[userId].Where(m => m.Id != modelId).ToList();
        }
    }

    public static void SendLogin(string userId, Action<ChatModel> action)
    {
        if (Dictionary.ContainsKey(userId))
        {
            foreach (var item in Dictionary[userId])
            {
                action.Invoke(item);
                item.State = 1; }}}}Copy the code
/// <summary>
///A record of a message
/// </summary>
public class ChatModel
{
    /// <summary>
    ///Each entry is assigned a unique Id
    /// </summary>
    public string Id { get; set; }
    /// <summary>
    ///Source code
    /// </summary>
    public string FromId { get; set; }
    /// <summary>
    ///The target number
    /// </summary>
    public string ToId { get; set; }
    /// <summary>
    ///The message content
    /// </summary>
    public string Message { get; set; }
    /// <summary>
    ///The message of time
    /// </summary>
    public DateTime CreateTime { get; set; }
    /// <summary>
    ///Message status 0 Unsent 1 Sent to be confirmed 2 Received
    /// </summary>
    public int State { get; set; }}Copy the code

Basic use to get offline messages

public class Chat : CommandBase<ChatSession.StringRequestInfo>
{
   public override void ExecuteCommand(ChatSession session, StringRequestInfo requestInfo)
   {
       // Again, two parameters are passed: 1, to whom to send ToId, 2, message content
       if(requestInfo.Parameters ! =null && requestInfo.Parameters.Length == 2)
       {
           string toId = requestInfo.Parameters[0];
           string message = requestInfo.Parameters[1];
           ChatSession toSession = session.AppServer.GetAllSessions().FirstOrDefault(a => toId.Equals(a.Id));
            
           string modelId = Guid.NewGuid().ToString();
           if(toSession ! =null) // said that a user had logged in with this Id before
           {
               toSession.Send($"{session.Id}Send you a message:{message} {modelId}");
               ChatDataManager.Add(toId, new ChatModel()
               {
                   FromId = session.Id,
                   ToId = toId,
                   Message = message,
                   Id = modelId,
                   State = 1./ / to be confirmed
                   CreateTime = DateTime.Now
               });
           }
           else
           {
               ChatDataManager.Add(toId, new ChatModel()
               {
                   FromId = session.Id,
                   ToId = toId,
                   Message = message,
                   Id = modelId,
                   State = 0./ / not sent
                   CreateTime = DateTime.Now
               }); 
               session.Send("Message was not sent successfully"); }}else
       {
           session.Send("Parameter error"); }}}Copy the code
public class Confirm : CommandBase<ChatSession.StringRequestInfo>
{
    public override void ExecuteCommand(ChatSession session, StringRequestInfo requestInfo)
    { 
        if(requestInfo.Parameters ! =null && requestInfo.Parameters.Length == 1)
        {
            string modelId = requestInfo.Parameters[0]; 
            Console.WriteLine($" user{session.Id}Confirmed. Message received{modelId}");
            ChatDataManager.Remove(session.Id, modelId);
        }
        else
        {
            session.Send("Parameter error"); }}}Copy the code

Heartbeat detection: sends messages periodically and reconnects if no message is received

public class HB : CommandBase<ChatSession.StringRequestInfo>
{
    public override void ExecuteCommand(ChatSession session, StringRequestInfo requestInfo)
    {
        if(requestInfo.Parameters ! =null && requestInfo.Parameters.Length == 1)
        {
            if ("R".Equals(requestInfo.Parameters[0]))
            {
                session.LastHbTime = DateTime.Now;
                session.Send("R");
            }
            else
            {
                session.Send("Parameter error"); }}else
        {
            session.Send("Parameter error"); }}}Copy the code

use

public class SuperSocketMain
    {
         
        //1 SuperSocket is introduced and used
        //2 User login in chatroom & unique login
        //3 Sending an online message & confirming receipt & Offline message
        //4 Heartbeat detection mechanism & disconnection and reconnection
        //5 CommandFilterAttribute AOP mechanism

        public static void Init()
        {
            // Can be configured through the configuration file to run the SuperSocket service;
            // Need to read the configuration file to start the service;
            try
            {
                // The service can be started by reading configuration files
                IBootstrap bootstrap = BootstrapFactory.CreateBootstrap();
                if(! bootstrap.Initialize()) { Console.WriteLine("Initialization failed");
                    Console.ReadKey();
                    return;
                }
                Console.WriteLine("Ready to start service");
                var result = bootstrap.Start();

                foreach (var server in bootstrap.AppServers)
                {
                    if (server.State == ServerState.Running)
                    {
                        Console.WriteLine($"{server.Name}In the operation of the");
                    }
                    else
                    {
                        Console.WriteLine($"{server.Name}Startup failed"); } } } catch (Exception ex) { Console.WriteLine(ex.Message); } Console.Read(); }}Copy the code

Two: the use of WebSocket

<form id="form1" runat="server">
    <div>
        <input id="userName" type="text" />
        <input id="conn" type="button" value="Connection" />
        <input id="close" type="button" value="Closed" />
        <span id="tips"></span>
        <input id="content" type="text" />
        <input id="send" type="button" value="Send" />
    </div>
    <div id="view">
        <ul></ul>
    </div>
</form>
<script src="~ / Scripts/jquery - 3.3.1. Js." "></script>

<script type="text/javascript">
    $(function () {
        // http:// https://
        // start with ws or WSS
        var socket;
        var url = "ws://localhost:57211/Home/MyWebSocket";
        function connect() {
            var socketurl = url + "? name=" + $("#userName").val();
            socket = new WebSocket(socketurl);// Is used to establish instant messaging peer Socket long links
            // There will be a handshake
            // The background methods to remove links can be MVC controller methods, WebApi, general handler support, or ASPX support

            // When the link is opened
            socket.onopen = function () {
                $("#tips").text("Link opened");
                  // Periodically sends a heartbeat packet to the server. The server sends a heartbeat packet to the client immediately after receiving the heartbeat packet
                   // If I do not receive a heartbeat message from the server within 10 seconds or more, I consider the connection to be down
                 // Disconnect connect();
            }
            // Accept the message sent by the server
            socket.onmessage = function (evt) { 
                $("#view ul").append("<li>" + evt.data + "</li>"); 
            }
            // The method is triggered when an exception occurs
            socket.onerror = function (evt) {
                $("#tips").text(JSON.stringify(evt));
            }
            // Triggered when the link is closed
            socket.onclose = function () {
                $("#tips").text("Connection closed."); }}// Click the "Connect" button
        $("#conn").on("click", function () {
            connect();
        })
        // Click the "Close" button
        $("#close").on("click", function () {
            socket.close();
        })

        // Click the "Send" button
        $("#send").on("click", function () {
            if (socket.readyState == WebSocket.OPEN) {
                socket.send($("#content").val());
            }
            else {
                alert("The link is broken.");
            } 
        })
    })
</script>
Copy the code

The back-end processing

public class HomeController : Controller
{
    public ActionResult WebSocket()
    {
        return View();
    }



    private string UserName = string.Empty;

    /// <summary>
    ///WebSocket method for establishing links
    /// </summary>
    /// <param name="name"></param>
    public void MyWebSocket(string name)
    {
        if (HttpContext.IsWebSocketRequest)
        {
            this.UserName = name;
            HttpContext.AcceptWebSocketRequest(ProcessChat);
        }
        else
        {
            HttpContext.Response.Write("I don't deal with it."); }}public async Task ProcessChat(AspNetWebSocketContext socketContext)
    {
        // SuperSocket:Session
        // represents a link to which the client initiates the request
        System.Net.WebSockets.WebSocket socket = socketContext.WebSocket;

        CancellationToken token = new CancellationToken();

        string socketGuid = Guid.NewGuid().ToString();

        OldChatManager.AddUser(socketGuid, UserName, socket, token);
         
        await OldChatManager.SengdMessage(token, UserName, "Enter a chat room");
        while (socket.State == WebSocketState.Open)
        {
            ArraySegment<byte> buffer = new ArraySegment<byte> (new byte[2048]);
            WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, token);
            string userMessage = Encoding.UTF8.GetString(buffer.Array, 0, result.Count); // Message content from the client


            if (result.MessageType == WebSocketMessageType.Close)
            {
                OldChatManager.RemoveUser(socketGuid);
                await OldChatManager.SengdMessage(token, UserName, "Leave the chat room");
                await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, token);
            }
            else
            {
                awaitOldChatManager.SengdMessage(token, UserName, userMessage); }}}}Copy the code

Related classes

public class SocketModel
{
    /// <summary>
    ///The unique ID of the link
    /// </summary>
    public string SocketGuid { get; set; }

    /// <summary>
    ///The user name
    /// </summary>
    public string UserName { get; set; }

    /// <summary>
    ///The Socket instance corresponding to each user link in
    /// </summary>
    public WebSocket Socket { get; set; }}Copy the code
public class OldChatManager
{
    ///A group should have a fixed number of people;
    /// <summary>
    ///By default, there are some people in a group
    ///1. There are four people in the group by default;
    /// </summary>
    public static List<SocketModel> socketlist = new List<SocketModel>() {
         new SocketModel(){ SocketGuid=string.Empty,UserName="User1",Socket=null },
         new SocketModel(){ SocketGuid=string.Empty,UserName="User2",Socket=null },
         new SocketModel(){ SocketGuid=string.Empty,UserName="User3",Socket=null },
         new SocketModel(){ SocketGuid=string.Empty,UserName="User4",Socket=null}};ArraySegment
      
        : The message to be sent
      
    public static Dictionary<string.List<ArraySegment<byte>>> chatList = new Dictionary<string, List<ArraySegment<byte> > > ();public static void AddUser(string socketGuid, string userName, WebSocket socket, CancellationToken token)
    {
        socketlist.ForEach(item =>
        {
            if(userName == item.UserName) { item.Socket = socket; item.SocketGuid = socketGuid; }});if (chatList.ContainsKey(userName) && chatList[userName].Count > 0)
        {
            foreach (var item in chatList[userName])
            {
                socket.SendAsync(item, WebSocketMessageType.Text, true, token); }}}public static void RemoveUser(string socketGuid)
    {
        socketlist.ForEach(item =>
        {
            if (socketGuid == item.SocketGuid)
            {
                item.Socket = null;
                item.SocketGuid = null; }}); }/// <summary>
    ///Group messages include offline messages
    /// </summary>
    /// <param name="token"></param>
    /// <param name="userName"></param>
    /// <param name="content"></param>
    /// <returns></returns>
    public static async Task SengdMessage(CancellationToken token, string userName, string content)
    {
        ArraySegment<byte> buffer = new ArraySegment<byte> (new byte[2048]); 
        buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes($"{DateTime.Now.ToString("Yyyy MM :ss: FFF")}{userName}:{content}"));

        foreach (var socketInfo in socketlist)
        {
            if (socketInfo.Socket == null)
            {
                if (chatList.ContainsKey(socketInfo.UserName))
                {
                    chatList[socketInfo.UserName].Add(buffer);
                }
                else
                {
                    chatList.Add(socketInfo.UserName, new List<ArraySegment<byte>>() { buffer }); }}else
            {
                await socketInfo.Socket.SendAsync(buffer, WebSocketMessageType.Text, true, token); }}}public static async Task Say(CancellationToken token, string userName, string content)
    {
        ArraySegment<byte> buffer = new ArraySegment<byte> (new byte[2048]);
        buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes($"{DateTime.Now.ToString("Yyyy MM :ss: FFF")}{userName}:{content}"));

        foreach (var socketInfo in socketlist)
        {
            if(socketInfo.Socket! =null)
            {
                await socketInfo.Socket.SendAsync(buffer, WebSocketMessageType.Text, true, token); }}}}Copy the code
public class ChatManager
{
    /// <summary>
    ///Each Socket corresponds to a client and server connection (also known as a user).
    ///  
    /// </summary>
    public static List<SocketModel> socketlist = new List<SocketModel>();

    //SocketModel is recommended to save in NoSql Redis MongoDb;

    public static void SendOne(string messge, CancellationToken cancellationToken)
    {
        // user1; hello
        string[] messageArray = messge.Split(':');  //toUser:Message;
        string toUser = messageArray[0];
        string toMessage = messageArray[1];
        var socketModel = socketlist.FirstOrDefault(a => toUser.Equals(a.UserName));
        if(socketModel ! =null)
        {
            WebSocket toSocket = socketModel.Socket;
            ArraySegment<byte> buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(toMessage)); 
            toSocket.SendAsync(buffer, WebSocketMessageType.Text, true, cancellationToken); }}/// <summary>
    ///Add a user (including the Socket for that user)
    /// </summary>
    /// <param name="socketGuid"></param>
    /// <param name="userName"></param>
    /// <param name="socket"></param>
    public static void AddUser(string socketGuid, string userName, WebSocket socket)
    {
        socketlist.Add(new SocketModel()
        {
            SocketGuid = socketGuid,
            UserName = userName,
            Socket = socket
        });
    }

    /// <summary>
    ///Delete a connected user
    /// </summary>
    /// <param name="socketGuid"></param>
    public static void RemoveUser(string socketGuid){ socketlist = socketlist.Where(a => a.SocketGuid ! = socketGuid).ToList(); }/// <summary>
    ///Group-sent message
    /// </summary>
    /// <param name="token"></param>
    /// <param name="userName"></param>
    /// <param name="content"></param>
    /// <returns></returns>
    public static async Task SengdMessage(CancellationToken token, string userName, string content)
    {
        ///WebSocket Format for sending messages Length of message content
        ArraySegment<byte> buffer = new ArraySegment<byte> (new byte[2048]);

        buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes($"{DateTime.Now.ToString("Yyyy MM :ss: FFF")}{userName}:{content}"));

        ///Send a message to each Socket (similar to a broadcast)
        foreach (var socketInfo in socketlist)
        {
            await socketInfo.Socket.SendAsync(buffer, WebSocketMessageType.Text, true, token); }}}Copy the code