WebSocket:使用第三方库做一个服务端

前言

相信大家在做web项目的时候可能都会遇到某些信息弹窗,提醒之类的功能,最简单粗暴的方式就是轮询,比如每秒浏览器从服务器发起http请求,然后服务器返回最新的结果过来。所以这种一直循环方式有很大的缺陷,浪费带宽资源、被动、单向。因为HTML5定义了WebSocket协议,WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议,简单来说能够达到客户端与服务端的双向,更多的介绍大家可以去网上搜搜,就不多说了,下面开始做一个.net的WebSocket的服务端。

开始写服务端

为了简单的实现我们的效果,这里我是建一个WinForm项目作为我们的服务端

(一)新建一个.net framework4.5的WinForm项目

在这里插入图片描述

(二)选择一个适合自己的第三方websocket库

打开万能的开源项目网站https://github.com选择下载一款自己喜欢的websocket开源库,这里我用的是WebSocket-Sharp(里面也有相关的使用说明文档),看个人喜好,至于每种库的好坏对比,就不评论了。
在这里插入图片描述
将https://github.com/sta/websocket-sharp下载下来,打开项目,生成编译,然后将生成的dll引用到我们项目里面来。在这里插入图片描述
这里要特别说明下websocket-sharp的核心WebSocketBehavior,他包含了OnOpen,OnMessage,OnClose,OnError四个方法以及一个Sessions对象。熟悉websocket的都知道前四个方法是用来处理客户端链接、发送消息、链接关闭以及出错。sessions就是用来管理所有的回话连接。每产生一个连接,都会有一个新Id,sessions中会新增一个IWebSocketSession对象。当页面关闭或者刷新都会触发OnClose,继而sessions中会移除对应的IwebSocketSession对象。
在这里插入图片描述

(三)自定义新增一个继承WebSocketBehavior的处理类

新增一个TestHandler类,继承WebSocketBehavior,TestHandler相当于是一个websocket的服务,你可以创建多个websocketBehavior的实例然后在挂载在websocketServer上。

    public class TestHandler : WebSocketBehavior
    {
        public Label lbUserCount;
        public TextBox showText;
        private Dictionary<string, string> nameList = new Dictionary<string, string>();
        protected override void OnOpen()
        {
            base.OnOpen();
            AppendValue("建立连接" + this.ID + "\r\n");
            nameList.Add(this.ID, "游客" + Sessions.Count);
            Broadcast(string.Format("{0}上线了,共有{1}人在线", nameList[this.ID], Sessions.Count), "3");
            ShowCount();

        }
        protected override void OnMessage(MessageEventArgs e)
        {
            base.OnMessage(e);
            string strMsg = e.Data;
            
            try
            {
                var obj = JsonConvert.DeserializeObject<ReceiveMsg>(strMsg);
                AppendValue("收到消息:" + obj.Message + " 类型:" + obj.MsgType + "id:" + this.ID + "\r\n");
                switch (obj.MsgType)
                {
                    //正常聊天
                    case "1":
                        obj.UserName = nameList[this.ID];
                        Sessions.Broadcast(JsonConvert.SerializeObject(obj));
                        break;
                    //修改名称
                    case "2":
                        AppendValue(string.Format("{0}修改名称{1} \r\n", nameList[this.ID], obj.Message));
                        Broadcast(string.Format("{0}修改名称{1}", nameList[this.ID], obj.Message), "3");
                        nameList[this.ID] = obj.Message;
                        break;
                    default:
                        Sessions.Broadcast(strMsg);
                        break;

                }
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception);
            }
        }
        protected override void OnClose(CloseEventArgs e)
        {
            base.OnClose(e);
            AppendValue("连接关闭" + this.ID + "\r\n");
            Broadcast(string.Format("{0}下线,共有{1}人在线", nameList[this.ID], Sessions.Count), "3");
            nameList.Remove(this.ID);
            ShowCount();
        }


        /// <summary>
        /// 广播(群发)
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="type"></param>
        private void Broadcast(string msg, string type = "1")
        {
            var data = new ReceiveMsg() { Message = msg, MsgType = type, UserName = nameList[this.ID] };
            Sessions.Broadcast(JsonConvert.SerializeObject(data));
        }
        /// <summary>
        /// 在线人数
        /// </summary>
        private void ShowCount()
        {
            //this.lbUserCount.Text = Sessions.Count.ToString();
            // 无返回值无参数用MethodInvoker委托,无返回值可有参数用Action委托,有返回值可有参数用Func委托
            lbUserCount.BeginInvoke(new Action<string>(msg => lbUserCount.Text = msg),
                new object[] { Sessions.Count.ToString() });
        }
        public void AppendValue(string strValue)
        {
            // 无返回值无参数用MethodInvoker委托,无返回值可有参数用Action委托,有返回值可有参数用Func委托
            showText.BeginInvoke(new Action<string>(msg => showText.Text += msg+DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")),
                new object[] { strValue });
        }


    }

From窗体代码

    public partial class Form1 : Form
    {
        private WebSocketServer wssv;
        private bool isStart = false;
        public Form1()
        {
            InitializeComponent();
            this.ShowListenStatus();
        }
        /// <summary>
        /// 启动
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                wssv = new WebSocketServer(Convert.ToInt32(textBox1.Text));
                wssv.AddWebSocketService<TestHandler>("/Test/", p =>
                {
                    p.lbUserCount = this.lbUserCount;
                    p.showText = this.showText;
                });
                wssv.Start();
                isStart = true;
                this.showText.Text += "连接成功!" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "\r\n";
                this.ShowListenStatus();
            }
            catch (Exception ee)
            {
                MessageBox.Show(ee.Message);
            }
        }

        /// <summary>
        /// 停止
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            wssv.Stop();
            isStart = false;
            this.lbUserCount.Text = "0";//重置为0
            this.showText.Text = "";//清空
            this.showText.Text += "连接断开!"+DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") +"\r\n";
            
            ShowListenStatus();
        }
        private void ShowListenStatus()
        {
            this.button2.Enabled = isStart ? true : false;
            this.button1.Enabled = isStart ? false : true;
        }
    }

运行测试效果
在这里插入图片描述

(四)写一个html5的聊天页面

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script type="text/javascript" src="scripts/jquery.js"></script>
<title>测试在线聊天</title>
</head>
 
<body>
 <div id="messages">
    </div>
	   <div>昵称:<input type="text" id="nickName"  /> <button id="changebt">修改</button> 
   </div>
   <div>消息内容:<input type="text" id="content" value=""/>
   <button id="sendbt">发送</button>
   </div>
</body>
<script type="text/javascript">
    function initWS() {
        ws = new WebSocket("ws://localhost:9600/Test");
        ws.onopen = function (e) {
            console.log("Openened connection to websocket");
            console.log(e);
        };

        ws.onmessage = function (e) {
            console.log("收到",e.data)
            var div=$("<div>");
            var data=JSON.parse(e.data);
            switch(data.MsgType){
                case "1":
             div.html(data.UserName+":"+data.Message);
            break;
                case "2":
                div.addClass("gray");
                div.html("修改名称"+data.Message)
                break;
                case "3":
                div.addClass("gray");
                div.html(data.Message)
                break;
            }
            $("#messages").append(div);
        };
		ws.onerror = function (msg) {

                console.log("socket error!");
        };
    }
    
    initWS();
    function sendMsg(msg,type){
        ws.send(JSON.stringify({Message:msg,MsgType:type}));
    }
    $("#sendbt").click(function(){
       var text=$("#content").val();
       sendMsg(text,"1")
       $("#content").val("");
    })
    $("#changebt").click(function(){
        var text=$("#nickName").val();
        sendMsg(text,"2")
    })
</script> 
</html>

测试截图
在这里插入图片描述

下面提供本项目相关的下载地址
websocket-sharp.dll:https://download.csdn.net/download/shaojiayong/12903143
项目完全源码(包含页面):https://download.csdn.net/download/shaojiayong/12903215

MFC是一个基于Windows平台的GUI应用程序框架,不直接支持WebSocket。不过,你可以使用第三方库来实现WebSocket服务端功能。 常用的WebSocket库有: - C++ REST SDK(Casablanca):由Microsoft开发的C++库,包含WebSocket服务器和客户端功能。 - Boost.Beast:Boost库中的一个HTTP和WebSocket实现库,提供了WebSocket服务器和客户端功能。 - WebSocket++:一个纯C++的WebSocket实现库。 在选择库之前,你需要考虑以下几点: - 你需要实现的WebSocket协议版本。 - 是否需要支持SSL/TLS加密协议。 - 是否需要跨平台支持。 以C++ REST SDK为例,以下是一个简单的WebSocket服务端示例: ```c++ #include <cpprest/ws_listener.h> #include <iostream> using namespace web; using namespace web::websockets::listener; int main() { http_listener listener("http://localhost:8080"); websocket_listener ws_listener("ws://localhost:8080"); listener.support([&ws_listener](http::http_request req) { // 处理HTTP请求 // ... }); ws_listener.support([](websocket::http_header header) -> bool { // 校验WebSocket请求头 // ... return true; }); ws_listener.on_message([](websocket::message msg) { // 处理WebSocket消息 std::cout << msg.extract_string().get() << std::endl; }); ws_listener.open().wait(); while (true); return 0; } ``` 这个示例演示了如何使用C++ REST SDK实现WebSocket服务端。它监听本地的8080端口,并处理HTTP请求和WebSocket消息。当WebSocket连接建立时,它会输出接收到的消息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hello,Mr.S

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值