• 仿微信 即时聊天工具


    话不多说,先上图

    背景:

    微信聊天,经常会遇见视频发不了,嗯,还有聊天不方便的问题,于是我就自己买了服务器,部署了一套可以直接在微信打开的网页进行聊天,这样只需要发送个url给朋友,就能聊天了!

    由于自己无聊弄着玩的,代码比较粗糙,各位多指正!

    1、首先安装SignalR,这步我就不做过多说明了

    安装好以后在根目录新建一个Hubs文件夹,做用户的注册和通知

    MessageHub.cs 文件

    using Microsoft.AspNet.SignalR;
    using Microsoft.AspNet.SignalR.Hubs;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Web;
    
    namespace SignalR.Hubs
    {
        [HubName("MessageHub")]
        public class MessageHub : Hub
            {
                private readonly ChatTicker ticker;
                public MessageHub()
                {
                    ticker = ChatTicker.Instance;
                }
    
                public void register(string username, string group = "default")
                {
                    var list = (List<SiginalRModel>)HttpRuntime.Cache.Get("msg_hs");
                    if (list == null)
                    {
                        list = new List<SiginalRModel>();
                    }
                   
    
                    if (list.Any(x => x.connectionId == Context.ConnectionId))
                    {
                        Clients.Client(Context.ConnectionId).broadcastMessage("已经注册,无需再次注册");
                    }
                else if (list.Any(x => x.name == username))
                {
                    var model = list.Where(x => x.name == username && x.group == group).FirstOrDefault();
                    if (model != null)
                    {
                        //注册到全局  
                        ticker.GlobalContext.Groups.Add(Context.ConnectionId, group);
                        Clients.Client(model.connectionId).exit();
                        ticker.GlobalContext.Groups.Remove(model.connectionId, group);
                        list.Remove(model);
                        model.connectionId = Context.ConnectionId;
                        list.Add(model);
                        Clients.Group(group).removeUserList(model.connectionId);
                        Thread.Sleep(200);
                        var gourpList = list.Where(x => x.group == group).ToList();
                        Clients.Group(group).appendUserList(Context.ConnectionId, gourpList);
                        HttpRuntime.Cache.Insert("msg_hs", list);
                        // Clients.Client(model.connectionId).broadcastMessage("名称重复,只能注册一个");
                    }
                    //Clients.Client(Context.ConnectionId).broadcastMessage("名称重复,只能注册一个");
                }
                else
                    {
                        list.Add(new SiginalRModel() { name = username, group = group, connectionId = Context.ConnectionId });
    
                        //注册到全局  
                        ticker.GlobalContext.Groups.Add(Context.ConnectionId, group);
                        Thread.Sleep(200);
    
                        var gourpList = list.Where(x => x.group == group).ToList();
                        Clients.Group(group).appendUserList(Context.ConnectionId, gourpList);
                        HttpRuntime.Cache.Insert("msg_hs", list);
                    }
    
                }
    
                public void Say(string msg)
                {
                    var list = (List<SiginalRModel>)HttpRuntime.Cache.Get("msg_hs");
                    if (list == null)
                    {
                        list = new List<SiginalRModel>();
                    }
                    var userModel = list.Where(x => x.connectionId == Context.ConnectionId).FirstOrDefault();
                    if (userModel != null )
                    {
                        Clients.Group(userModel.group).Say(userModel.name, msg);
                    }
                }
    
            public void Exit()
            {
                OnDisconnected(true);
            }
    
            public override Task OnDisconnected(bool s)
                    {
                        var list = (List<SiginalRModel>)HttpRuntime.Cache.Get("msg_hs");
                        if (list == null)
                        {
                            list = new List<SiginalRModel>();
                        }
                        var closeModel = list.Where(x => x.connectionId == Context.ConnectionId).FirstOrDefault();
    
                        if (closeModel != null)
                        {
                            list.Remove(closeModel);
    
                            Clients.Group(closeModel.group).removeUserList(Context.ConnectionId);
    
                         }
                        HttpRuntime.Cache.Insert("msg_hs", list);
                    
                        return base.OnDisconnected(s);
                    }
                }
            
    
        public class ChatTicker
            {
                #region 实现一个单例
    
                private static readonly ChatTicker _instance =
                    new ChatTicker(GlobalHost.ConnectionManager.GetHubContext<MessageHub>());
    
                private readonly IHubContext m_context;
    
                private ChatTicker(IHubContext context)
                {
    
                    m_context = context;
                    //这里不能直接调用Sender,因为Sender是一个不退出的“死循环”,否则这个构造函数将不会退出。  
                    //其他的流程也将不会再执行下去了。所以要采用异步的方式。  
                    //Task.Run(() => Sender());
                }
    
                public IHubContext GlobalContext
                {
                    get { return m_context; }
                }
    
                public static ChatTicker Instance
                {
                    get { return _instance; }
                }
    
                #endregion
            }
    
        public class SiginalRModel {
            public string connectionId { get; set; }
    
            public string group { get; set; }
            public string name { get; set; }
        }
    }

    我把类和方法都写到一块了,大家最好是分开!

    接下来是控制器

    HomeController.cs

    using Microsoft.AspNet.SignalR;
    using Microsoft.AspNet.SignalR.Client;
    using SignalR.Hubs;
    using SignalR.ViewModels;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using Newtonsoft.Json;
    using System.Diagnostics;
    using System.Text.RegularExpressions;
    
    namespace SignalR.Controllers
    {
        public class HomeController : Controller
        {
            public ActionResult Index()
            {
        
                return View();
            }
    
    
            public ActionResult GetV(string v)
            {
                if (!string.IsNullOrEmpty(v))
                {
                    string url = RedisHelper.Get(v)?.ToString();
                    if (!string.IsNullOrEmpty(url))
                    {
                        return Json(new { isOk = true, m = url }, JsonRequestBehavior.AllowGet);
                    }
                    return Json(new { isOk = false}, JsonRequestBehavior.AllowGet);
                }
                return Json(new { isOk = false }, JsonRequestBehavior.AllowGet);
            }
    
            public ActionResult getkey(string url)
            {
                if (!string.IsNullOrEmpty(url))
                {
                    var s = "v" + Util.GetRandomLetterAndNumberString(new Random(), 5).ToLower();
                    var dt = Convert.ToDateTime(DateTime.Now.AddDays(1).ToString("yyyy-MM-dd 04:00:00"));
                    int min = Convert.ToInt16((dt - DateTime.Now).TotalMinutes);
                    RedisHelper.Set(s, url, min);
                    return Json(new { isOk = true, m = s }, JsonRequestBehavior.AllowGet);
                }
                return Json(new { isOk = false }, JsonRequestBehavior.AllowGet);
            }
    
            public ActionResult upfile()
            {
                try
                {
                    if (Request.Files.Count > 0)
                    {
                        var file = Request.Files[0];
                        if (file != null)
                        {
                            var imgList = new List<string>() { ".gif", ".jpg", ".bmp", ".png" };
                            var videoList = new List<string>() { ".mp4" };
                            FileModel fmodel = new FileModel();
    
                            string name = Guid.NewGuid().ToString();
                            string fileExt = Path.GetExtension(file.FileName).ToLower();//上传文件扩展名
                            string path = Server.MapPath("~/files/") + name + fileExt;
                            file.SaveAs(path);
    
                            string extension = new FileInfo(path).Extension;
    
                            if (extension == ".mp4")
                            {
                                fmodel.t = 2;
                            }
                            else if (imgList.Contains(extension))
                            {
                                fmodel.t = 1;
                            }
                            else
                            {
                                fmodel.t = 0;
                            }
                            string url = Guid.NewGuid().ToString();
                            fmodel.url = "http://" + Request.Url.Host;
                            if (Request.Url.Port != 80)
                            {
                                fmodel.url += ":" + Request.Url.Port;
                            }
                            fmodel.url += "/files/" + name + fileExt;
                            GetImageThumb(Server.MapPath("~") + "files\" + name + fileExt, name);
                            return Json(new { isOk = true, m = "file:" + JsonConvert.SerializeObject(fmodel) }, JsonRequestBehavior.AllowGet);
                        }
                    }
                }
                catch(Exception ex)
                {
                    Log.Info(ex);
                }
               
               
                return Content("");
            }
    
            public string GetImageThumb(string localVideo,string name)
            {
                string path = AppDomain.CurrentDomain.BaseDirectory;
                string ffmpegPath = path + "/ffmpeg.exe";
                string oriVideoPath = localVideo;
                int frameIndex = 5;
                int _thubWidth;
                int _thubHeight;
                GetMovWidthAndHeight(localVideo, out _thubWidth, out _thubHeight);
                int thubWidth = 200;
                int thubHeight = _thubWidth == 0 ? 200 : (thubWidth * _thubHeight / _thubWidth );  
                
                string thubImagePath = path +  "files\" + name + ".jpg";
                string command = string.Format(""{0}" -i "{1}" -ss {2} -vframes 1 -r 1 -ac 1 -ab 2 -s {3}*{4} -f image2 "{5}"", ffmpegPath, oriVideoPath, frameIndex, thubWidth, thubHeight, thubImagePath);
                Cmd.RunCmd(command);
                return name;
            }
    
            /// <summary>
            /// 获取视频的帧宽度和帧高度
            /// </summary>
            /// <param name="videoFilePath">mov文件的路径</param>
            /// <returns>null表示获取宽度或高度失败</returns>
            public static void GetMovWidthAndHeight(string videoFilePath, out int width, out int height)
            {
                try
                {
    
                    //执行命令获取该文件的一些信息 
                    string ffmpegPath = AppDomain.CurrentDomain.BaseDirectory +  "/ffmpeg.exe";
                    string output;
                    string error;
                    ExecuteCommand(""" + ffmpegPath + """ + " -i " + """ + videoFilePath + """, out output, out error);
                    if (string.IsNullOrEmpty(error))
                    {
                        width = 0;
                        height = 0;
                    }
    
                    //通过正则表达式获取信息里面的宽度信息
                    Regex regex = new Regex("(\d{2,4})x(\d{2,4})", RegexOptions.Compiled);
                    Match m = regex.Match(error);
                    if (m.Success)
                    {
                        width = int.Parse(m.Groups[1].Value);
                        height = int.Parse(m.Groups[2].Value);
                    }
                    else
                    {
                        width = 0;
                        height = 0;
                    }
                }
                catch (Exception)
                {
                    width = 0;
                    height = 0;
                }
            }
    
            public static void ExecuteCommand(string command, out string output, out string error)
            {
                try
                {
                    //创建一个进程
                    Process pc = new Process();
                    pc.StartInfo.FileName = command;
                    pc.StartInfo.UseShellExecute = false;
                    pc.StartInfo.RedirectStandardOutput = true;
                    pc.StartInfo.RedirectStandardError = true;
                    pc.StartInfo.CreateNoWindow = true;
    
                    //启动进程
                    pc.Start();
    
                    //准备读出输出流和错误流
                    string outputData = string.Empty;
                    string errorData = string.Empty;
                    pc.BeginOutputReadLine();
                    pc.BeginErrorReadLine();
    
                    pc.OutputDataReceived += (ss, ee) =>
                    {
                        outputData += ee.Data;
                    };
    
                    pc.ErrorDataReceived += (ss, ee) =>
                    {
                        errorData += ee.Data;
                    };
    
                    //等待退出
                    pc.WaitForExit();
    
                    //关闭进程
                    pc.Close();
    
                    //返回流结果
                    output = outputData;
                    error = errorData;
                }
                catch (Exception)
                {
                    output = null;
                    error = null;
                }
            }
    
        }
    
        public class Util
        {
            public static string GetRandomLetterAndNumberString(Random random, int length)
            {
                if (length < 0)
                {
                    throw new ArgumentOutOfRangeException("length");
                }
                char[] pattern = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
            'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
                string result = "";
                int n = pattern.Length;
                for (int i = 0; i < length; i++)
                {
                    int rnd = random.Next(0, n);
                    result += pattern[rnd];
                }
                return result;
            }
        }
    
        class Cmd
        {
            private static string CmdPath = @"C:WindowsSystem32cmd.exe";
            /// <summary>
            /// 执行cmd命令 返回cmd窗口显示的信息
            /// 多命令请使用批处理命令连接符:
            /// <![CDATA[
            /// &:同时执行两个命令
            /// |:将上一个命令的输出,作为下一个命令的输入
            /// &&:当&&前的命令成功时,才执行&&后的命令
            /// ||:当||前的命令失败时,才执行||后的命令]]>
            /// </summary>
            /// <param name="cmd">执行的命令</param>
            public static string RunCmd(string cmd)
            {
                cmd = cmd.Trim().TrimEnd('&') + "&exit";//说明:不管命令是否成功均执行exit命令,否则当调用ReadToEnd()方法时,会处于假死状态
                using (Process p = new Process())
                {
                    p.StartInfo.FileName = CmdPath;
                    p.StartInfo.UseShellExecute = false;        //是否使用操作系统shell启动
                    p.StartInfo.RedirectStandardInput = true;   //接受来自调用程序的输入信息
                    p.StartInfo.RedirectStandardOutput = true;  //由调用程序获取输出信息
                    p.StartInfo.RedirectStandardError = true;   //重定向标准错误输出
                    p.StartInfo.CreateNoWindow = true;          //不显示程序窗口
                    p.Start();//启动程序
    
                    //向cmd窗口写入命令
                    p.StandardInput.WriteLine(cmd);
                    p.StandardInput.AutoFlush = true;
    
                    //获取cmd窗口的输出信息
                    string output = p.StandardOutput.ReadToEnd();
                    p.WaitForExit();//等待程序执行完退出进程
                    p.Close();
    
                    return output;
                }
            }
        }
    }

    我还是都写到一块了,大家记得分开!

    SController.cs  这个是针对手机端单独拎出来的,里面不需要什么内容

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    
    namespace SignalR.Controllers
    {
        public class SController : Controller
        {
            // GET: S
            public ActionResult Index()
            {
                return View();
            }
        }
    }
    

     根目录新建一个ViewModels文件夹,里面新建FileModel.cs文件

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    
    namespace SignalR.ViewModels
    {
        public class FileModel
        {
            /// <summary>
            /// 1 : 图片  2:视频
            /// </summary>
            public int t { get; set; }
    
            public string url { get; set; }
        }
    } 

    RedisHelper.cs

    using Microsoft.AspNet.SignalR.Messaging;
    using StackExchange.Redis;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Runtime.Serialization.Formatters.Binary;
    using System.Threading.Tasks;
    using System.Web;
    
    namespace SignalR
    {
        public class RedisHelper
        {
            private static string Constr = "xxxx.cn:6379";
    
            private static object _locker = new Object();
            private static ConnectionMultiplexer _instance = null;
    
            /// <summary>
            /// 使用一个静态属性来返回已连接的实例,如下列中所示。这样,一旦 ConnectionMultiplexer 断开连接,便可以初始化新的连接实例。
            /// </summary>
            public static ConnectionMultiplexer Instance
            {
                get
                {
                    if (Constr.Length == 0)
                    {
                        throw new Exception("连接字符串未设置!");
                    }
                    if (_instance == null)
                    {
                        lock (_locker)
                        {
                            if (_instance == null || !_instance.IsConnected)
                            {
                                _instance = ConnectionMultiplexer.Connect(Constr);
                            }
                        }
                    }
                    //注册如下事件
                    _instance.ConnectionFailed += MuxerConnectionFailed;
                    _instance.ConnectionRestored += MuxerConnectionRestored;
                    _instance.ErrorMessage += MuxerErrorMessage;
                    _instance.ConfigurationChanged += MuxerConfigurationChanged;
                    _instance.HashSlotMoved += MuxerHashSlotMoved;
                    _instance.InternalError += MuxerInternalError;
                    return _instance;
                }
            }
    
            static RedisHelper()
            {
            }
    
    
            /// <summary>
            /// 
            /// </summary>
            /// <returns></returns>
            public static IDatabase GetDatabase()
            {
                return Instance.GetDatabase();
            }
    
            /// <summary>
            /// 这里的 MergeKey 用来拼接 Key 的前缀,具体不同的业务模块使用不同的前缀。
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            private static string MergeKey(string key)
            {
                return "SignalR:"+ key;
                //return BaseSystemInfo.SystemCode + key;
            }
    
            /// <summary>
            /// 根据key获取缓存对象
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="key"></param>
            /// <returns></returns>
            public static T Get<T>(string key)
            {
                key = MergeKey(key);
                return Deserialize<T>(GetDatabase().StringGet(key));
            }
    
            /// <summary>
            /// 根据key获取缓存对象
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            public static object Get(string key)
            {
                key = MergeKey(key);
                return Deserialize<object>(GetDatabase().StringGet(key));
            }
    
            /// <summary>
            /// 设置缓存
            /// </summary>
            /// <param name="key"></param>
            /// <param name="value"></param>
            /// <param name="expireMinutes"></param>
            public static void Set(string key, object value, int expireMinutes = 0)
            {
                key = MergeKey(key);
                if (expireMinutes > 0)
                {
                    GetDatabase().StringSet(key, Serialize(value), TimeSpan.FromMinutes(expireMinutes));
                }
                else
                {
                    GetDatabase().StringSet(key, Serialize(value));
                }
    
            }
    
    
            /// <summary>
            /// 判断在缓存中是否存在该key的缓存数据
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            public static bool Exists(string key)
            {
                key = MergeKey(key);
                return GetDatabase().KeyExists(key); //可直接调用
            }
    
            /// <summary>
            /// 移除指定key的缓存
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            public static bool Remove(string key)
            {
                key = MergeKey(key);
                return GetDatabase().KeyDelete(key);
            }
    
            /// <summary>
            /// 异步设置
            /// </summary>
            /// <param name="key"></param>
            /// <param name="value"></param>
            public static async Task SetAsync(string key, object value)
            {
                key = MergeKey(key);
                await GetDatabase().StringSetAsync(key, Serialize(value));
            }
    
            /// <summary>
            /// 根据key获取缓存对象
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            public static async Task<object> GetAsync(string key)
            {
                key = MergeKey(key);
                object value = await GetDatabase().StringGetAsync(key);
                return value;
            }
    
            /// <summary>
            /// 实现递增
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            public static long Increment(string key)
            {
                key = MergeKey(key);
                //三种命令模式
                //Sync,同步模式会直接阻塞调用者,但是显然不会阻塞其他线程。
                //Async,异步模式直接走的是Task模型。
                //Fire - and - Forget,就是发送命令,然后完全不关心最终什么时候完成命令操作。
                //即发即弃:通过配置 CommandFlags 来实现即发即弃功能,在该实例中该方法会立即返回,如果是string则返回null 如果是int则返回0.这个操作将会继续在后台运行,一个典型的用法页面计数器的实现:
                return GetDatabase().StringIncrement(key, flags: CommandFlags.FireAndForget);
            }
    
            /// <summary>
            /// 实现递减
            /// </summary>
            /// <param name="key"></param>
            /// <param name="value"></param>
            /// <returns></returns>
            public static long Decrement(string key, string value)
            {
                key = MergeKey(key);
                return GetDatabase().HashDecrement(key, value, flags: CommandFlags.FireAndForget);
            }
    
            /// <summary>
            /// 序列化对象
            /// </summary>
            /// <param name="o"></param>
            /// <returns></returns>
            private static byte[] Serialize(object o)
            {
                if (o == null)
                {
                    return null;
                }
                BinaryFormatter binaryFormatter = new BinaryFormatter();
                using (MemoryStream memoryStream = new MemoryStream())
                {
                    binaryFormatter.Serialize(memoryStream, o);
                    byte[] objectDataAsStream = memoryStream.ToArray();
                    return objectDataAsStream;
                }
            }
    
            /// <summary>
            /// 反序列化对象
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="stream"></param>
            /// <returns></returns>
            private static T Deserialize<T>(byte[] stream)
            {
                if (stream == null)
                {
                    return default(T);
                }
                BinaryFormatter binaryFormatter = new BinaryFormatter();
                using (MemoryStream memoryStream = new MemoryStream(stream))
                {
                    T result = (T)binaryFormatter.Deserialize(memoryStream);
                    return result;
                }
            }
    
            /// <summary>
            /// 配置更改时
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private static void MuxerConfigurationChanged(object sender, EndPointEventArgs e)
            {
                //LogHelper.SafeLogMessage("Configuration changed: " + e.EndPoint);
            }
    
            /// <summary>
            /// 发生错误时
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private static void MuxerErrorMessage(object sender, RedisErrorEventArgs e)
            {
                //LogHelper.SafeLogMessage("ErrorMessage: " + e.Message);
            }
    
            /// <summary>
            /// 重新建立连接之前的错误
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private static void MuxerConnectionRestored(object sender, ConnectionFailedEventArgs e)
            {
                //LogHelper.SafeLogMessage("ConnectionRestored: " + e.EndPoint);
            }
    
            /// <summary>
            /// 连接失败 , 如果重新连接成功你将不会收到这个通知
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private static void MuxerConnectionFailed(object sender, ConnectionFailedEventArgs e)
            {
                //LogHelper.SafeLogMessage("重新连接:Endpoint failed: " + e.EndPoint + ", " + e.FailureType +(e.Exception == null ? "" : (", " + e.Exception.Message)));
            }
    
            /// <summary>
            /// 更改集群
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private static void MuxerHashSlotMoved(object sender, HashSlotMovedEventArgs e)
            {
                //LogHelper.SafeLogMessage("HashSlotMoved:NewEndPoint" + e.NewEndPoint + ", OldEndPoint" + e.OldEndPoint);
            }
    
            /// <summary>
            /// redis类库错误
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private static void MuxerInternalError(object sender, InternalErrorEventArgs e)
            {
                //LogHelper.SafeLogMessage("InternalError:Message" + e.Exception.Message);
            }
    
            //场景不一样,选择的模式便会不一样,大家可以按照自己系统架构情况合理选择长连接还是Lazy。
            //建立连接后,通过调用ConnectionMultiplexer.GetDatabase 方法返回对 Redis Cache 数据库的引用。从 GetDatabase 方法返回的对象是一个轻量级直通对象,不需要进行存储。
    
            /// <summary>
            /// 使用的是Lazy,在真正需要连接时创建连接。
            /// 延迟加载技术
            /// 微软azure中的配置 连接模板
            /// </summary>
            //private static Lazy<ConnectionMultiplexer> lazyConnection = new Lazy<ConnectionMultiplexer>(() =>
            //{
            //    //var options = ConfigurationOptions.Parse(constr);
            //    ////options.ClientName = GetAppName(); // only known at runtime
            //    //options.AllowAdmin = true;
            //    //return ConnectionMultiplexer.Connect(options);
            //    ConnectionMultiplexer muxer = ConnectionMultiplexer.Connect(Coonstr);
            //    muxer.ConnectionFailed += MuxerConnectionFailed;
            //    muxer.ConnectionRestored += MuxerConnectionRestored;
            //    muxer.ErrorMessage += MuxerErrorMessage;
            //    muxer.ConfigurationChanged += MuxerConfigurationChanged;
            //    muxer.HashSlotMoved += MuxerHashSlotMoved;
            //    muxer.InternalError += MuxerInternalError;
            //    return muxer;
            //});
    
    
            #region  当作消息代理中间件使用 一般使用更专业的消息队列来处理这种业务场景
    
            /// <summary>
            /// 当作消息代理中间件使用
            /// 消息组建中,重要的概念便是生产者,消费者,消息中间件。
            /// </summary>
            /// <param name="channel"></param>
            /// <param name="message"></param>
            /// <returns></returns>
            public static long Publish(string channel, string message)
            {
                StackExchange.Redis.ISubscriber sub = Instance.GetSubscriber();
                //return sub.Publish("messages", "hello");
                return sub.Publish(channel, message);
            }
    
            /// <summary>
            /// 在消费者端得到该消息并输出
            /// </summary>
            /// <param name="channelFrom"></param>
            /// <returns></returns>
            public static void Subscribe(string channelFrom)
            {
                StackExchange.Redis.ISubscriber sub = Instance.GetSubscriber();
                sub.Subscribe(channelFrom, (channel, message) =>
                {
                    Console.WriteLine((string)message);
                });
            }
    
            #endregion
    
            /// <summary>
            /// GetServer方法会接收一个EndPoint类或者一个唯一标识一台服务器的键值对
            /// 有时候需要为单个服务器指定特定的命令
            /// 使用IServer可以使用所有的shell命令,比如:
            /// DateTime lastSave = server.LastSave();
            /// ClientInfo[] clients = server.ClientList();
            /// 如果报错在连接字符串后加 ,allowAdmin=true;
            /// </summary>
            /// <returns></returns>
            public static IServer GetServer(string host, int port)
            {
                IServer server = Instance.GetServer(host, port);
                return server;
            }
    
            /// <summary>
            /// 获取全部终结点
            /// </summary>
            /// <returns></returns>
            public static EndPoint[] GetEndPoints()
            {
                EndPoint[] endpoints = Instance.GetEndPoints();
                return endpoints;
            }
        }
    }
    

      

     总体项目结构是这样的

    下期我将把前端代码列出来,这个我只是为了实现功能,大神勿喷

  • 相关阅读:
    三、LIKE和通配符
    二、SQL基本语法
    一、认识SQL
    修改配置文件:my.ini
    SQL——创建表、更改表、删除表
    SQL——更新和删除
    windows下svn更新ubuntu共享目录,主机拒绝的问题。
    Debian/Ubuntu包安装工具APT的使用
    samba无法修正错误,因为您要求某些软件包保持现状,就是它们破坏了软件包间的依赖关系
    虚拟机中的ip局域网中其他机子ping不通
  • 原文地址:https://www.cnblogs.com/colyn/p/11976006.html
Copyright © 2020-2023  润新知