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

一、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地址改成服务器地址即可。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python:熟悉简单的skfuzzy构建接近生活事件的模糊控制器”(附带详细注释说明)+ 测试结果

参考资料&#xff1a;https: // blog.csdn.net / shelgi / article / details / 126908418 ————通过下面这个例子&#xff0c;终于能理解一点模糊理论的应用了&#xff0c;感谢原作。 熟悉简单的skfuzzy构建接近生活事件的模糊控制器 假设下面这样的场景, 我们希望构建一套…

隐语笔记3 —— 隐语架构

隐语架构一览 隐语产品层 定位&#xff1a; 通过可视化产品&#xff0c;降低终端用户的体验和演示成本。通过模块化API降低技术集成商的研发成本。 人群画像&#xff1a; 隐私保护计算集成商&#xff0c;产品人员&#xff0c;隐私保护计算需求方&#xff0c;开发人员&#xff…

2024年全球生成人工智能全景图【中文】

2024年全球生成人工智能全景图【中文】 在过去的一年中&#xff0c;产生式人工智能&#xff08;GenAI&#xff09;无疑成为了全球各行各业的热门话题。特别是ChatGPT的发布&#xff0c;激发了公众对GenAI强烈的兴趣和激动&#xff0c;唤醒了我们对其变革潜力的认知。 虽然我们…

Redis中的缓存雪崩

缓存雪崩 &#x1f914;现象分析 缓存雪崩是指在同一时段大量的缓存key同时失效或者缓存服务(Redis等)宕机&#xff0c;导致大量请求到达数据库&#xff0c;带来巨大压力。 &#x1f44a; 解决方案 利用Redis集群提高服务的可用性&#xff0c;避免缓存服务宕机给缓存业务添…

软件架构和基于架构的软件开发方法知识总结

一、软件架构定义 软件架构为软件系统提供了一个结构、行为和属性的高级抽象 软件架构是一种表达&#xff0c;使软件工程师能够&#xff1a; &#xff08;1&#xff09;分析设计在满足所规定的需求方面的有效性 &#xff08;2&#xff09;在设计变更相对容易的阶段&#xff0c;…

当我想用ChatGPT-Next-Web来套壳Azure OpenAI Service时

使用Cloudflare worker来代理Azure OpenAI API&#xff0c; 并将其转换为兼容OpenAI的API 一直没能搞定OpenAI的订阅&#xff0c; 就因为没有搞定国外的信用卡&#xff0c; 所以就一直使用GPT-3.5来处理日常的文字生成工作&#xff0c; 例如写文档&#xff0c; 生成一些简单的脚…

python网络相册设计与实现flask-django-nodejs-php

此系统设计主要采用的是python语言来进行开发&#xff0c;采用django框架技术&#xff0c;框架分为三层&#xff0c;分别是控制层Controller&#xff0c;业务处理层Service&#xff0c;持久层dao&#xff0c;能够采用多层次管理开发&#xff0c;对于各个模块设计制作有一定的安…

前端学习笔记 | AJAX

一、axios 是什么&#xff1a;AJAX是异步的JavaScript和XML。它可以在不重新刷新页面的情况下与服务器通信&#xff0c;交换数据&#xff0c;或更新页面。 概念&#xff1a;AJAX是浏览器与服务器进行数据通信的技术。 1、使用axios库与服务器进行数据通信 &#xff08;1&#x…

skywalking监听apisix

一、原理 Skywalking结合OpenTelemetry Collector Apisix的promethus插件实现对apisix metrics数据的收集。 二、数据流图 1. Apisix Promethus插件从Apisix收集指标数据。 2. OpenTelemetry Collector通过promethus receiver获取来自Apisix Promethus插件的指标数据&#…

Codeforces Round 498 (Div. 3)

目录 A. Adjacent Replacements B. Polycarps Practice C. Three Parts of the Array D. Two Strings Swaps E. Military Problem F. Xor-Paths A. Adjacent Replacements 简单思维题 每一个数都变成第一个小于等于自己的的奇数 void solve(){cin>>n;while(n--){…

现在阿里云云服务器租用多少钱?一张表,报价单

2024年阿里云服务器优惠价格表&#xff0c;一张表整理阿里云服务器最新报价&#xff0c;阿里云服务器网整理云服务器ECS和轻量应用服务器详细CPU内存、公网带宽和系统盘详细配置报价单&#xff0c;大家也可以直接移步到阿里云CLUB中心查看 aliyun.club 当前最新的云服务器优惠券…

c++核心学习5

4.6继承 有些类与类之间存在特殊的关系&#xff0c;例如下图中&#xff1a; 我们发现&#xff0c;定义这些类时&#xff0c;下级别的成员除了拥有上一级的共性&#xff0c;还有自己的特性。这个时候我们就可以考虑利用继承的技术&#xff0c;减少重复代码 4.6.1继承的基本语法…

Nature:“量子龙卷风”首次模拟黑洞

科学家们在超流体氦气中首次创造出了一个巨大的“量子漩涡”&#xff08;quantum vortex&#xff09;&#xff0c;用以模拟黑洞。这一成就不仅使他们能够更加细致地观察模拟黑洞的行为&#xff0c;还能探究其与周围环境的交互作用。 诺丁汉大学的研究团队与伦敦国王学院和纽卡斯…

酷开会员 |酷开科技通过酷开系统让内容和用户完成适配

互联网大屏电视的趋势早有&#xff0c;从智能电视发行时就已见苗头&#xff0c;不过随着各大厂商在技术上的不断革新、模式上的不断突进&#xff0c;OTT模式给电视机行业带来了新一轮的风口。不论是什么企业或者行业&#xff0c;想要提升整体的效益&#xff0c;从效益层面来讲&…

后端程序员入门react笔记(九)- react 插件使用

setState setState引起的react的状态是异步的。操作完毕setState之后如果直接取值&#xff0c;可能取不到最新的值&#xff0c;我们举个例子console.log(this.state.num)打印的值&#xff0c;总是上一次的值而不是最新的。 import React, {Component} from react; class Ap…

[linux][调度] 内核抢占入门 —— 线程调度次数与 CONFIG_PREEMPTION

在工作中&#xff0c;如果你正在做开发的工作&#xff0c;正在在写代码&#xff0c;这个时候测试同事在测试过程中测出了问题&#xff0c;需要你来定位解决&#xff0c;那么你就应该先暂停写代码的工作&#xff0c;转而来定位解决测试的问题&#xff1b;如果你正在定位测试的问…

瑞_23种设计模式_状态模式

文章目录 1 状态模式&#xff08;State Pattern&#xff09;1.1 介绍1.2 概述1.3 状态模式的结构1.4 状态模式的优缺点1.5 状态模式的使用场景 2 案例一2.1 需求2.2 代码实现&#xff08;未使用状态模式&#xff09;2.3 代码实现&#xff08;状态模式&#xff09; 3 案例二3.1 …

数据中台:如何构建企业核心竞争力_光点科技

在当今信息化快速发展的商业环境下&#xff0c;“数据中台”已经成为构建企业核心竞争力的关键步骤。数据中台不仅是数据集成与管理的平台&#xff0c;更是企业智能化转型的加速器。本文将深入探讨数据中台的定义、特点、构建方法及其在企业中的作用。 数据中台的定义 数据中台…

基于python+vue的stone音乐播放器的设计与实现flask-django-php-nodejs

随着我国经济的高速发展与人们生活水平的日益提高&#xff0c;人们对生活质量的追求也多种多样。尤其在人们生活节奏不断加快的当下&#xff0c;人们更趋向于足不出户解决生活上的问题&#xff0c;stone音乐播放器展现了其蓬勃生命力和广阔的前景。与此同时&#xff0c;为解决用…

2024年通信工程专业-毕业论文

2024年毕业设计-通信专业VoLTE掉话分析资源-CSDN文库 毕业设计 ----移动通信中VoLTE信令流程分析 学生姓名 专业班级 学 号 指导教师 完成时间 …