基于NetCoreServer的WebSocket客户端实现群播(学习笔记)

news2024/11/17 5:01:04

一、NetCoreServer介绍

超快速、低延迟的异步套接字服务器和客户端 C# .NET Core 库,支持 TCP、SSL、UDP、HTTP、HTTPS、WebSocket 协议和 10K 连接问题解决方案。
客户端
开源地址:https://github.com/chronoxor/NetCoreServer
支持:
Example: TCP chat server
Example: TCP chat client
Example: SSL chat server
Example: SSL chat client
Example: UDP echo server
Example: UDP echo client
Example: UDP multicast server
Example: UDP multicast client
Example: Unix Domain Socket chat server
Example: Unix Domain Socket chat client
Example: Simple protocol
Example: Simple protocol server
Example: Simple protocol client
Example: HTTP server
Example: HTTP client
Example: HTTPS server
Example: HTTPS client
Example: WebSocket chat server
Example: WebSocket chat client
Example: WebSocket secure chat server
Example: WebSocket secure chat client
本文重点学习WebSocket通讯

二、服务端及双客户端代码

在这里插入图片描述

2.1 服务端控制台

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using NetCoreServer;

namespace WsChatServer
{
    class ChatSession : WsSession
    {
        public ChatSession(WsServer server) : base(server) {}

        public override void OnWsConnected(HttpRequest request)
        {
            Console.WriteLine($"Chat WebSocket session with Id {Id} connected!");

            // Send invite message
            string message = "Hello from WebSocket chat! Please send a message or '!' to disconnect the client!";
            SendTextAsync(message);
        }

        public override void OnWsDisconnected()
        {
            Console.WriteLine($"Chat WebSocket session with Id {Id} 已断开!");
        }

        public override void OnWsReceived(byte[] buffer, long offset, long size)
        {
            string message = Encoding.UTF8.GetString(buffer, (int)offset, (int)size);
            Console.WriteLine("来自: " + message);

            // Multicast message to all connected sessions
            ((WsServer)Server).MulticastText(message);

            // If the buffer starts with '!' the disconnect the current session
            if (message == "!")
                Close();
        }

        protected override void OnError(SocketError error)
        {
            Console.WriteLine($"Chat WebSocket session caught an error with code {error}");
        }
    }

    class ChatServer : WsServer
    {
        public ChatServer(IPAddress address, int port) : base(address, port) {}

        protected override TcpSession CreateSession() { return new ChatSession(this); }

        protected override void OnError(SocketError error)
        {
            Console.WriteLine($"错误 {error}");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // WebSocket server port 服务端口
            int port = 9999;
            if (args.Length > 0)
                port = int.Parse(args[0]);

            // WebSocket server content path
            string www = "../../../../../www/ws";
            if (args.Length > 1)
                www = args[1];

            Console.WriteLine($"WebSocket 服务端口: {port}");
            Console.WriteLine($"WebSocket server static content path: {www}");
            Console.WriteLine($"WebSocket server website: http://localhost:{port}/chat/index.html");

            Console.WriteLine();

            // Create a new WebSocket server
            var server = new ChatServer(IPAddress.Any, port);
            server.AddStaticContent(www, "/chat");

            // Start the server
            Console.Write("服务端启动...");
            server.Start();
            Console.WriteLine("完成!");

            Console.WriteLine("Press Enter to stop the server or '!' to restart the server...");

            // Perform text input
            for (;;)
            {
                string line = Console.ReadLine();//接受输入
                if (string.IsNullOrEmpty(line))
                    break;

                // Restart the server
                if (line == "!")
                {//重启标识!
                    Console.Write("Server restarting...");
                    server.Restart();
                    Console.WriteLine("Done!");
                }

                // Multicast admin message to all sessions
                line = "[管理员] " + line;   //前缀admin管理员消息
                server.MulticastText(line);//广播
            }

            // Stop the server
            Console.Write("服务端停止...");
            server.Stop();
            Console.WriteLine("完成!");
        }
    }
}

2.2 客户端html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>WebSocket聊天客户端示例</title>
  <link rel="icon" type="image/png" href="./favicon.png"/>
</head>
<body>
  <script>
 var myname;
 var isconned=false;
 
//初始化
  function init()
  {
    document.myform.url.value = "ws://localhost:9999/"//不要和系统的端口冲突
    document.myform.inputtext.value = "Hello World!"//问候语
    document.myform.disconnectButton.disabled = true//断开连接默认禁用
  }
//打开连接
  function doConnect()
  {
	isconned=true;
    websocket = new WebSocket(document.myform.url.value)
    websocket.onopen = function(evt) { onOpen(evt) }
    websocket.onclose = function(evt) { onClose(evt) }
    websocket.onmessage = function(evt) { onMessage(evt) }
    websocket.onerror = function(evt) { onError(evt) }
  }
//打开
  function onOpen(evt)
  {
    writeToScreen("connected\n")
    document.myform.connectButton.disabled = true
    document.myform.disconnectButton.disabled = false
	myname=document.myform.myname.value
  }
//关闭
  function onClose(evt)
  {
    writeToScreen("disconnected\n")
    document.myform.connectButton.disabled = false
    document.myform.disconnectButton.disabled = true
  }
//发消息
  function onMessage(evt)
  {
    writeToScreen("接收<<" + evt.data + '\n')
  }
//错误
  function onError(evt)
  {
    writeToScreen('error: ' + evt.data + '\n')

    websocket.close()//关闭websocket

    document.myform.connectButton.disabled = false//启用连接
    document.myform.disconnectButton.disabled = true//断开禁用
  }
//发送消息
  function doSend(message)
  {
    writeToScreen("发送>>" + message + '\n')//回显
    websocket.send(message)//发送到服务端
  }
//输出到屏幕
  function writeToScreen(message)
  {
    document.myform.outputtext.value += message//拼接
    document.myform.outputtext.scrollTop = document.myform.outputtext.scrollHeight//滚动到底部
  }
//监听
  window.addEventListener("load", init, false)
//发送方法
  function sendText()
  {
    var msg=document.myform.inputtext.value;
    if(msg==""||isconned==false)
	{
	    alert("对不起,请输入内容或先连接");
		return;
	}
	
	doSend("["+myname+"] "+msg)//消息内容
  }
//清屏
  function clearText()
  {
    document.myform.outputtext.value = ""
  }
//断开连接
  function doDisconnect()
  {
    isconned=false;
    websocket.close()
  }

  </script>
  <h3>WebSocket Client</h3>
  <form name="myform">
    <p>
	  <li>姓名:<input name="myname" value="X5ZJ" class="txt" /><li>
      <li>地址:<input name="url" class="txt"/></li>
	  <li>
	    <input type="button" name=connectButton value="连接" onClick="doConnect()">
		<input type="button" name=disconnectButton value="断开" onClick="doDisconnect()">
	  </li>
    </p>
    <p>
      <textarea name="outputtext" cols="35" rows="10" readonly>聊天记录</textarea>
    </p>
    <p>
      内容:<input name="inputtext" class="txt"/>
    </p>
    <p>
      <input type="button" name=sendButton value="发送" onClick="sendText()">
      <input type="button" name=clearButton value="清屏" onClick="clearText()">
    </p>
 </form>
 <style>
 p{line-height:20px;padding:4px}
 .txt{width:200px}
 li{list-style-type:none;margin:2px}
 </style>
</body>
</html>

2.3 客户端控制台

using System;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using NetCoreServer;

namespace WsChatClient
{
    class ChatClient : WsClient
    {
        public ChatClient(string address, int port) : base(address, port) {}

        public void DisconnectAndStop()
        {
            _stop = true;
            CloseAsync(1000);
            while (IsConnected)
                Thread.Yield();
        }

        public override void OnWsConnecting(HttpRequest request)
        {
            request.SetBegin("GET", "/");
            request.SetHeader("Host", "localhost");
            request.SetHeader("Origin", "http://localhost");
            request.SetHeader("Upgrade", "websocket");
            request.SetHeader("Connection", "Upgrade");
            request.SetHeader("Sec-WebSocket-Key", Convert.ToBase64String(WsNonce));
            request.SetHeader("Sec-WebSocket-Protocol", "chat, superchat");
            request.SetHeader("Sec-WebSocket-Version", "13");
            request.SetBody();
        }

        public override void OnWsConnected(HttpResponse response)
        {
            Console.WriteLine($"Chat WebSocket client connected a new session with Id {Id}");
        }

        public override void OnWsDisconnected()
        {
            Console.WriteLine($"Chat WebSocket client disconnected a session with Id {Id}");
        }

        public override void OnWsReceived(byte[] buffer, long offset, long size)
        {
            Console.WriteLine($"Incoming: {Encoding.UTF8.GetString(buffer, (int)offset, (int)size)}");
        }

        protected override void OnDisconnected()
        {
            base.OnDisconnected();

            Console.WriteLine($"Chat WebSocket client disconnected a session with Id {Id}");

            // Wait for a while...
            Thread.Sleep(1000);

            // Try to connect again
            if (!_stop)
                ConnectAsync();
        }

        protected override void OnError(SocketError error)
        {
            Console.WriteLine($"Chat WebSocket client caught an error with code {error}");
        }

        private bool _stop;
    }

    class Program
    {
        static void Main(string[] args)
        {
            // WebSocket server address
            string address = "127.0.0.1";
            if (args.Length > 0)
                address = args[0];

            // WebSocket server port 服务端口一致 9999
            int port = 9999;
            if (args.Length > 1)
                port = int.Parse(args[1]);

            Console.WriteLine($"WebSocket server address: {address}");
            Console.WriteLine($"WebSocket server port: {port}");

            Console.WriteLine();

            // Create a new TCP chat client
            var client = new ChatClient(address, port);

            // Connect the client
            Console.Write("Client connecting...");
            client.ConnectAsync();//连接
            Console.WriteLine("Done!");

            Console.WriteLine("Press Enter to stop the client or '!' to reconnect the client...");

            //获取Guid值作为随机数种子
            string guid = System.Guid.NewGuid().ToString();
            Random random = new Random(guid.GetHashCode());
            string IdPart = random.Next(10000, 99999).ToString();
            
            // Perform text input
            for (;;)
            {
                string line = Console.ReadLine();//接受输入
                if (string.IsNullOrEmpty(line))
                    break;

                // Disconnect the client
                if (line == "!")
                {//端口连接符!
                    Console.Write(IdPart+"Client disconnecting...");
                    client.SendTextAsync(IdPart+",will be disconnecting...");
                    client.DisconnectAsync();
                    Console.WriteLine("Done!");
                    continue;
                }

                // Send the entered text to the chat server 发送内容
                client.SendTextAsync(string.Format("[{0}] {1} ({2})", IdPart,line,DateTime.Now.ToString("MM-dd HH:mm:ss FFF")));//客户端发送
            }

            // Disconnect the client
            Console.Write("Client disconnecting...");
            client.DisconnectAndStop();//断开
            Console.WriteLine("Done!");
        }
    }
}

客户端可以继续优化实现群聊。注意服务端口和ws地址改成服务器地址即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1538141.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

分享Pandas 数据分析实战课程

分享Pandas 数据分析实战课程&#xff0c;3 小时掌握数据分析核心技能。 链接&#xff1a;https://pan.baidu.com/s/1Ikk3I1dfoFO0id3EBZJdGg?pwd4y83 提取码&#xff1a;4y83 链接&#xff1a;https://pan.quark.cn/s/fa2acd7513f4 提取码&#xff1a;yWu7

【3DsMax】展UV记录

目录 一、概念 二、边的颜色 三、UV的连续性 四、合理的划分UV接缝 五、总结 一、概念 展uv的概念可以理解为把三维的模型铺平展成一个平面&#xff0c;然后在这个平面上去绘制图案。 二、边的颜色 我们先创建一个长方体&#xff0c;然后在修改器列表中添加“UVW展开”…

数据格式化方法

首先你需要一个可以展示代码的组件&#xff1b; 我使用的是tech-ui(内部组件库)&#xff1b; 你如果没有类似的组件&#xff0c;可以参考以下链接替代&#xff1a; react-monaco-editor -- 代码编辑器(适用Umi)_umi monaco editor-CSDN博客 Codemirror -- 代码编辑器(react…

schweizer-electronic 公司 safedat2 操作使用说明

schweizer-electronic 公司 safedat2 操作使用说明

优质的短效HTTP代理具备什么优点?

随着网络时代的蓬勃发展&#xff0c;数据的获取与处理成为了企业决策和市场竞争的关键。在这场数据的角逐中&#xff0c;优质的短效HTTP代理脱颖而出&#xff0c;备受业界瞩目。优质的短效HTTP代理&#xff0c;提供了稳定的网络连接和匿名性&#xff0c;更为数据采集提供了关键…

css设置div的2个span一个在最左边,一个在最右边

界面&#xff1a; 代码&#xff1a; <html><style>.top span {display: block;position: absolute;margin: 0 20px; /* 添加边距以避免太靠近边缘 */ }.top span:nth-child(1) {left: 5px; /* 调整左侧位置 */ }.top span:nth-child(2) {right: 5px; /* 调整右侧位…

1.6 学Python能干什么,Python的应用领域有哪些

Python能干什么&#xff0c;Python的应用领域 Python 作为一种功能强大的编程语言&#xff0c;因其简单易学而受到很多开发者的青睐。那么&#xff0c;Python 的应用领域有哪些呢&#xff1f; Python 有着非广泛的应用&#xff0c;几乎所有大中型互联网公司都在使用 Python&a…

推荐一款很不错的vscode高亮插件

用过很多款高亮插件&#xff0c;总感觉大部分显示都很乱&#xff0c;但是其中有一款用起来很清晰明了&#xff0c;很喜欢&#xff01; 插件名字&#xff1a;select-highlight-cochineal-color 使用效果&#xff1a; 底色高亮让人感觉很清晰&#xff0c;一个好的高亮插件能让你…

鸿蒙一次开发,多端部署(九)应用市场首页

本小节将以应用市场首页为例&#xff0c;介绍如何使用自适应布局能力和响应式布局能力适配不同尺寸窗口。 页面设计 一个典型的应用市场首页的UX设计如下所示。 观察应用市场首页的页面设计&#xff0c;不同断点下的页面设计有较多相似的地方。 据此&#xff0c;我们可以将页…

2024蓝桥杯每日一题(单调队列)

备战2024年蓝桥杯 -- 每日一题 Python大学A组 试题一&#xff1a;单调栈 试题二&#xff1a;滑动窗口 试题三&#xff1a;子矩阵 试题四&#xff1a;最大子序和 试题一&#xff1a;单调栈 【题目描述】 给定一个长度为 N 的整数数列&#xff0c;输出每…

怿星科技Neptune CHT-S测试系统,让智能座舱测试更加高效便捷

随着汽车“智能化”浪潮的推进&#xff0c;汽车的智能化水平正在持续刷新行业认知。在这股智能化潮流中&#xff0c;智能座舱作为客户体验最为直观的部分&#xff0c;其重要性不言而喻。倘若座舱设备出现死机、黑屏、卡顿等现象&#xff0c;都将对客户的使用体验产生非常大的影…

Python Flask 表单的使用

新建templ;ates/index.html 内容如下 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body> <form action"">账号&#xff1a;<input …

Flutter Widget:StatefulWidgetStatelessWidgetState

Widget 概念 Widget 将是构建Flutter应用的基石&#xff0c;在Flutter开发中几乎所有的对象都是一个 Widget 。 在Flutter中的widget 不仅表示UI元素&#xff0c;也表示一些功能性的组件&#xff0c;如&#xff1a;手势 、主题Theme 等。而原生开发中的控件通常只是指UI元素。…

[Rust] 使用vscode实现HelloWorld程序并进行debug

一、简介 本文介绍了如何使用vscode编写rust&#xff0c;实现打印"Hello, world!"的程序。 二、工具安装 0. 环境介绍&#xff1a; Linux &#xff08;或者windowswsl&#xff09; 1. 安装rust编译器rustc和包管理器cargo。 请参考连接&#xff1a;Rust 程序设…

Skywalking的Helm Chart方式部署

背景 之前介绍了AWS云上面的EKS的集中日志方案。这次主要介绍调用链监控了&#xff0c;这里我们用的是Skywalking。监控三王者&#xff08;EFKPrometheusSkywalking&#xff09;之一。之前AWS云上面使用fluent bit替代EFK方案&#xff0c;其实&#xff0c;AWS云在调用链方面&a…

1Panel应用推荐:DataEase开源数据可视化分析工具

1Panel&#xff08;github.com/1Panel-dev/1Panel&#xff09;是一款现代化、开源的Linux服务器运维管理面板&#xff0c;它致力于通过开源的方式&#xff0c;帮助用户简化建站与运维管理流程。为了方便广大用户快捷安装部署相关软件应用&#xff0c;1Panel特别开通应用商店&am…

查看Scala类的方法

文章目录 一、概述如何查看Scala类的方法二、使用Scala文档查看类的方法三、使用反射机制查看类的方法 一、概述如何查看Scala类的方法 本文介绍了在Scala中查看Int类方法的两种方法&#xff1a;使用Scala标准库文档和使用反射机制。通过Scala标准库文档&#xff0c;您可以方便…

Qt 项目使用visual studio 进行开发调试

https://marketplace.visualstudio.com/items?itemNameTheQtCompany.QtVisualStudioTools2015 https://devblogs.microsoft.com/cppblog/bring-your-existing-qt-projects-to-visual-studio/ 正常Qt开发中&#xff0c;使用Qt Creator 进行windows下MSVC编译器的调试是一件挺麻…

jenkins构建完成后部署到本机,无法读取容器外文件夹

项目背景&#xff1a; Dockerjenkins 构建完成后&#xff0c;要把打包的dist文件夹内容移动到网站目录 /www/wwwroot/xxxxxx 文件夹下&#xff1b;但是获取不到jenkins容器外的文件夹。 解决办法&#xff1a; 在容器中&#xff0c;添加挂载/映射本机目录&#xff0c;把网站…

【C语言_数组_复习篇】

目录 一、数组的概念 二、数组的类型 三、一维数组 3.1 一维数组的创建 3.2 一维数组的初始化 3.3 一维数组的访问 3.4 一维数组在内存中的存储 四、二维数组 4.1 二维数组的创建 4.2 二维数组的初始化 4.3 二维数组的访问 4.4 二维数组在内存中的存储 五、变长数组 六、…