(精华)2020年8月20日 C#基础知识点 Socket的使用

(精华)2020年8月20日 C#基础知识点 Socket的使用

一:Socket的基本使用

tcp使用

服务端

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("监听已经打开,请等待");

    //收到消息  接受一个socket链接
    Socket serverSocket = sSocket.Accept();
    Console.WriteLine("连接已经建立。。。");
    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("服务器端获得信息:{0}", recStr);

        if (recStr.Equals("stop"))
        {<!-- -->
            serverSocket.Close();//关闭该socket对象
            Console.WriteLine("关闭链接。。。。");
            break;
        }

        //回发消息
        Console.WriteLine("请输入回发消息。。。。");
        string sendStr = Console.ReadLine(); //"send to client :hello world";
        byte[] sendByte = Encoding.ASCII.GetBytes(sendStr);
        serverSocket.Send(sendByte, sendByte.Length, 0);
    }
    sSocket.Close();//关闭server监听
}

客户端

static void Main(string[] args)
{<!-- -->
    try
    {<!-- -->
        Console.WriteLine("启动一个Socket客户端链接"); 
        int port = 2018;
        string host = "127.0.0.1";//服务器端ip地址 
        IPAddress ip = IPAddress.Parse(host);
        IPEndPoint ipe = new IPEndPoint(ip, port); 
        Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        clientSocket.Connect(ipe); //开启链接以后,是长链接; 
        while (true)
        {<!-- -->
            Console.WriteLine("请输入发送到服务器的信息:");
            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];
            //监控传递过来的消息;
            int bytes = clientSocket.Receive(recBytes, recBytes.Length, 0);
            recStr += Encoding.ASCII.GetString(recBytes, 0, bytes);
            Console.WriteLine($"服务器返回:{recStr}");
        }
        clientSocket.Close();
    }
    catch (Exception ex)
    {<!-- -->
        Console.WriteLine(ex.Message);
    }
    Console.Read();
}

UDP的使用

服务端

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));//绑定端口号和IP
            Console.WriteLine("服务端已经开启");
            Thread t = new Thread(ReciveMsg);//开启接收消息线程
            t.Start();
            Thread t2 = new Thread(sendMsg);//开启发送消息线程
            t2.Start();


        }
        /// <summary>
        /// 向特定ip的主机的端口发送数据报
        /// </summary>
        static void sendMsg()
        {<!-- -->
            EndPoint point = new IPEndPoint(IPAddress.Parse("169.254.202.67"), 6000);
            while (true)
            {<!-- -->
                string msg = Console.ReadLine();
                server.SendTo(Encoding.UTF8.GetBytes(msg), point);
            }


        }
        /// <summary>
        /// 接收发送给本机ip对应端口号的数据报
        /// </summary>
        static void ReciveMsg()
        {<!-- -->
            while (true)
            {<!-- -->
                EndPoint point = new IPEndPoint(IPAddress.Any, 0);//用来保存发送方的ip和端口号
                byte[] buffer = new byte[1024];
                int length = server.ReceiveFrom(buffer, ref point);//接收数据报
                string message = Encoding.UTF8.GetString(buffer,0,length);
                Console.WriteLine(point.ToString()+ message);

            }
        }


    }
}

客户端

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("客户端已经开启");
        }
        /// <summary>
        /// 向特定ip的主机的端口发送数据报
        /// </summary>
        static void sendMsg()
        {<!-- -->
            EndPoint point = new IPEndPoint(IPAddress.Parse("169.254.202.67"), 6001);
            while(true){<!-- -->
                string msg = Console.ReadLine();
                client.SendTo(Encoding.UTF8.GetBytes(msg), point);
            }


        }

        /// <summary>
        /// 接收发送给本机ip对应端口号的数据报
        /// </summary>
        static void ReciveMsg()
        {<!-- -->
            while (true)
            {<!-- -->
                EndPoint point = new IPEndPoint(IPAddress.Any, 0);//用来保存发送方的ip和端口号
                byte[] buffer = new byte[1024];
                int length = client.ReceiveFrom(buffer, ref point);//接收数据报
                string message = Encoding.UTF8.GetString(buffer, 0, length);
                Console.WriteLine(point.ToString() + message);
            }
        }

    }
}

二:SuperSocket的使用

首先安装:SuperSocket.Engine
SuperSoket的三大对象:

  1. Session: 每一个用户连接就是一个Session1. AppServer: Socket服务器实例1. Commands: 客户端向服务器发送消息的命令集合 首先在配置文件加入如下配置
<?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>
      <!-- 可以配置多个Server-->
    </servers>
  </superSocket>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
</configuration>

创建个ChatServer服务

[AuthorisizeFilter]
public class ChatServer:AppServer<ChatSession>
{<!-- -->
    protected override bool Setup(IRootConfig rootConfig, IServerConfig config)
    {<!-- -->
        Console.WriteLine("准备读取配置文件。。。。");
        return base.Setup(rootConfig, config);
    }

    protected override void OnStarted()
    {<!-- -->
        Console.WriteLine("Chat服务启动。。。");
        base.OnStarted();
    }

    protected override void OnStopped()
    {<!-- -->
        Console.WriteLine("Chat服务停止。。。");
        base.OnStopped();
    }

    /// <summary>
    /// 新的连接
    /// </summary>
    /// <param name="session"></param>
    protected override void OnNewSessionConnected(ChatSession session)
    {<!-- -->
        Console.WriteLine($"Chat服务新加入的连接:{session.LocalEndPoint.Address.ToString()}");
        base.OnNewSessionConnected(session);
    }
}
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("请先登录以后,再操作。。。");
                commandContext.Cancel = true;//不再继续往后走;
            }
            else
            {<!-- --> 
                ///....
            } 
        }
        else if (!session.IsOnLine)
        {<!-- -->
            session.LastHbTime = DateTime.Now;
        } 
    }
    public override void OnCommandExecuted(CommandExecutingContext commandContext)
    {<!-- -->
        //throw new NotImplementedException();
    }
}

创建个Session服务

/// <summary>
/// 表示用户连接
/// </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>
    /// 消息发送
    /// </summary>
    /// <param name="message"></param>
    public override void Send(string message)
    {<!-- -->
        Console.WriteLine($"准备发送给{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("收到命令:" + requestInfo.Key.ToString());
        this.Send("不知道如何处理 " + requestInfo.Key.ToString() + " 命令");
    }

    /// <summary>
    /// 异常捕捉
    /// </summary>
    /// <param name="e"></param>
    protected override void HandleException(Exception e)
    {<!-- -->
        this.Send($"\n\r异常信息:{ e.Message}");
        //base.HandleException(e);
    }

    /// <summary>
    /// 连接关闭
    /// </summary>
    /// <param name="reason"></param>
    protected override void OnSessionClosed(CloseReason reason)
    {<!-- -->
        Console.WriteLine("链接已关闭。。。");
        base.OnSessionClosed(reason);
    }
}

Commands代码如下 : 客户端发送消息命令 Check 1 123456
Check 代表类名 ,1代表session.id(会话ID),1代表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) // 说过之前有用户用这个Id 登录过
            {<!-- -->
                oldSession.Send("您的账号已经在他处登录,您已经被踢下线了");
                oldSession.Close();
            }

            #region 这里就可以连接数据库进行数据验证做登录
            ///---------------------
            #endregion
            session.Id = requestInfo.Parameters[0];
            session.PassWord = requestInfo.Parameters[1];
            session.IsLogin = true;
            session.LoginTime = DateTime.Now;

            session.Send("登录成功");

            {<!-- --> // 获取当前登录用户的离线消息 
                ChatDataManager.SendLogin(session.Id, c =>
                {<!-- --> 
                    session.Send($"{c.FromId} 给你发送消息:{c.Message} {c.Id}");
                });

            }
        }
        else
        {<!-- -->
            session.Send("参数错误");
        }
    }
}

离线消息存储的相关类

public class ChatDataManager
{<!-- -->
    /// <summary>
    /// key是用户id
    /// List 这个用户的全部消息
    /// </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] = new List<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;
            }
        }
    }
}
/// <summary>
/// 一条消息的记录
/// </summary>
public class ChatModel
{<!-- -->
    /// <summary>
    /// 每条分配个唯一Id
    /// </summary>
    public string Id {<!-- --> get; set; }
    /// <summary>
    /// 来源编号
    /// </summary>
    public string FromId {<!-- --> get; set; }
    /// <summary>
    /// 目标编号
    /// </summary>
    public string ToId {<!-- --> get; set; }
    /// <summary>
    /// 消息内容
    /// </summary>
    public string Message {<!-- --> get; set; }
    /// <summary>
    /// 消息时间
    /// </summary>
    public DateTime CreateTime {<!-- --> get; set; }
    /// <summary>
    /// 消息状态  0未发送 1已发送待确认  2确认收到
    /// </summary>
    public int State {<!-- --> get; set; }
}

基本使用获取离线消息

public class Chat : CommandBase<ChatSession, StringRequestInfo>
{<!-- -->
   public override void ExecuteCommand(ChatSession session, StringRequestInfo requestInfo)
   {<!-- -->
       // 还是传递两个参数  1、 要发给谁 ToId    2、消息内容
       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) // 说过之前有用户用这个Id 登录过
           {<!-- -->
               toSession.Send($"{session.Id} 给你发消息:{message} {modelId}");
               ChatDataManager.Add(toId, new ChatModel()
               {<!-- -->
                   FromId = session.Id,
                   ToId = toId,
                   Message = message,
                   Id = modelId,
                   State = 1,// 待确认
                   CreateTime = DateTime.Now
               });
           }
           else
           {<!-- -->
               ChatDataManager.Add(toId, new ChatModel()
               {<!-- -->
                   FromId = session.Id,
                   ToId = toId,
                   Message = message,
                   Id = modelId,
                   State = 0,// 未发送
                   CreateTime = DateTime.Now
               }); 
               session.Send("消息未发送成功");
           }
       }
       else
       {<!-- -->
           session.Send("参数错误");
       }
   }
}
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($"用户{session.Id} 已确认,收到消息{modelId}");
            ChatDataManager.Remove(session.Id, modelId);
        }
        else
        {<!-- -->
            session.Send("参数错误");
        }
    }
}

心跳检测:主要就是定时发送消息,没接到消息就发起重连

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("参数错误");
            }
        }
        else
        {<!-- -->
            session.Send("参数错误");
        }
    }
}

使用

public class SuperSocketMain
    {<!-- -->

        //1 SuperSocket引入和使用
        //2 聊天室之用户登录&唯一登陆
        //3 在线发消息&确认收到&离线消息
        //4 心跳检测机制&断线重连
        //5 CommandFilterAttribute的AOP机制

        public static void Init()
        {<!-- -->
            //可以通过配置文件来配置以后,运行SuperSocket服务;
            //需要读取配置文件启动服务;
            try
            {<!-- -->
                //支持通过配置文件读取对服务启动 
                IBootstrap bootstrap = BootstrapFactory.CreateBootstrap();
                if (!bootstrap.Initialize())
                {<!-- -->
                    Console.WriteLine("初始化失败");
                    Console.ReadKey();
                    return;
                }
                Console.WriteLine("准备启动服务");
                var result = bootstrap.Start();

                foreach (var server in bootstrap.AppServers)
                {<!-- -->
                    if (server.State == ServerState.Running)
                    {<!-- -->
                        Console.WriteLine($"{server.Name}运行中");
                    }
                    else
                    {<!-- -->
                        Console.WriteLine($"{server.Name}启动失败");
                    }
                }


            }
            catch (Exception ex)
            {<!-- -->
                Console.WriteLine(ex.Message);
            }
            Console.Read();

        }
    }

二:WebSocket的使用

<form id="form1" runat="server">
    <div>
        <input id="userName" type="text" />
        <input id="conn" type="button" value="连接" />
        <input id="close" type="button" value="关闭" />
        <span id="tips"></span>
        <input id="content" type="text" />
        <input id="send" type="button" value="发送" />
    </div>
    <div id="view">
        <ul></ul>
    </div>
</form>
<script src="~/Scripts/jquery-3.3.1.js"></script>

<script type="text/javascript">
    $(function () {<!-- -->
        // http://  https://
        // ws 开头, 也可以wss开头
        var socket;
        var url = "ws://localhost:57211/Home/MyWebSocket";
        function connect() {<!-- -->
            var socketurl = url + "?name=" + $("#userName").val();
            socket = new WebSocket(socketurl);// 就是用来建立即时通信同道 Socket长链接
            // 会有一个握手的过程
            // 去链接的后台方法可以是MVC控制器里的方法,也可以是WebApi,还可以支持一般处理程序,也可以支持aspx

            //链接打开的时候触发
            socket.onopen = function () {<!-- -->
                $("#tips").text("链接已打开");
                  // 定时发送一个消息给服务器发送心跳包 服务器接收到心跳包以后马上就再回复一个消息给客户端
                   // 如果我发现十秒钟或者在间隔时间内 接受不到服务器回复的心跳消息 我就认为连接掉线
                 // 这时候就需要断线 connect();
            }
            // 接受服务器发送过来的消息
            socket.onmessage = function (evt) {<!-- --> 
                $("#view ul").append("<li>" + evt.data + "</li>"); 
            }
            // 异常的时候触发方法
            socket.onerror = function (evt) {<!-- -->
                $("#tips").text(JSON.stringify(evt));
            }
            // 链接关闭的时候触发
            socket.onclose = function () {<!-- -->
                $("#tips").text("连接关闭了");
            }
        }

        // 点击"连接"按钮
        $("#conn").on("click", function () {<!-- -->
            connect();
        })
        //点击“关闭”按钮
        $("#close").on("click", function () {<!-- -->
            socket.close();
        })

        //点击“发送”按钮
        $("#send").on("click", function () {<!-- -->
            if (socket.readyState == WebSocket.OPEN) {<!-- -->
                socket.send($("#content").val());
            }
            else {<!-- -->
                alert("链接已经断开");
            } 
        })
    })
</script>

后端处理

public class HomeController : Controller
{<!-- -->
    public ActionResult WebSocket()
    {<!-- -->
        return View();
    }



    private string UserName = string.Empty;

    /// <summary>
    /// WebSocket建立链接的方法
    /// </summary>
    /// <param name="name"></param>
    public void MyWebSocket(string name)
    {<!-- -->
        if (HttpContext.IsWebSocketRequest)
        {<!-- -->
            this.UserName = name;
            HttpContext.AcceptWebSocketRequest(ProcessChat);
        }
        else
        {<!-- -->
            HttpContext.Response.Write("我不处理");
        }
    }


    public async Task ProcessChat(AspNetWebSocketContext socketContext)
    {<!-- -->
        //  SuperSocket:Session
        // 表示客户端发起请求的一个链接
        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, "进入聊天室");
        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); // 来自于客户端发送过来的消息内容 


            if (result.MessageType == WebSocketMessageType.Close)
            {<!-- -->
                OldChatManager.RemoveUser(socketGuid);
                await OldChatManager.SengdMessage(token, UserName, "离开聊天室");
                await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, token);
            }
            else
            {<!-- -->
                await OldChatManager.SengdMessage(token, UserName, userMessage);
            }
        }
    }
}

相关类

public class SocketModel
{<!-- -->
    /// <summary>
    /// 链接的唯一ID
    /// </summary>
    public string SocketGuid {<!-- --> get; set; }

    /// <summary>
    ///  用户名称
    /// </summary>
    public string UserName {<!-- --> get; set; }

    /// <summary>
    /// 每一个用户链接进来以后 对应的这一个Socket实例
    /// </summary>
    public WebSocket Socket {<!-- --> get; set; }
}
public class OldChatManager
{<!-- -->
    ///一个群就应该有固定的的人数;
    /// <summary>
    /// 默认某一个群组里面有这么一些人
    /// 1.默认这个群里就有四个人;
    /// </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 } 
    };
    // string: 要发谁   ArraySegment<byte>:要发送的消息
    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>
    ///  群发消息 包括离线消息
    /// </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月dd日 HH: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月dd日 HH:mm:ss:fff")}{userName}:{content}"));

        foreach (var socketInfo in socketlist)
        {<!-- -->
            if (socketInfo.Socket!=null)
            {<!-- -->
                await socketInfo.Socket.SendAsync(buffer, WebSocketMessageType.Text, true, token);
            } 
        }

    }
}
public class ChatManager
{<!-- -->
    /// <summary>
    /// 每一个Socket对应一个客户端和服务器的连接(也可理解成一个用户)
    ///  
    /// </summary>
    public static List<SocketModel> socketlist = new List<SocketModel>();

    //SocketModel 建议大家保存在NoSql  Redis  MongoDb;

    public static void SendOne(string messge, CancellationToken cancellationToken)
    {<!-- -->
        //   user1;你好
        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>
    /// 添加一个用户(包含了这个用户对应的Socket)
    /// </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>
    /// 删除已经连接的用户
    /// </summary>
    /// <param name="socketGuid"></param>
    public static void RemoveUser(string socketGuid)
    {<!-- -->
        socketlist = socketlist.Where(a => a.SocketGuid != socketGuid).ToList();
    }

    /// <summary>
    ///  群发消息
    /// </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 消息发送的格式 消息内容的长度
        ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);

        buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes($"{DateTime.Now.ToString("yyyy年MM月dd日 HH:mm:ss:fff")}{userName}:{content}"));

        ///给每一个Socket (用户) 发送消息 (类似于一个广播的形式)
        foreach (var socketInfo in socketlist)
        {<!-- -->
            await socketInfo.Socket.SendAsync(buffer, WebSocketMessageType.Text, true, token);
        }
    }
}
posted @ 2020-12-30 11:46  不要摸我的腰  阅读(372)  评论(0编辑  收藏  举报