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

相关推荐

  1. springboot实现nettywebsocket服务客户

    2024-03-23 06:14:04       38 阅读
  2. vue实现原生websocket客户(一)

    2024-03-23 06:14:04       14 阅读
  3. 基于WebFluxwebsocket分组和实现

    2024-03-23 06:14:04       35 阅读
  4. 基于C# Socket实现简单Redis客户

    2024-03-23 06:14:04       17 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-23 06:14:04       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-23 06:14:04       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-23 06:14:04       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-23 06:14:04       20 阅读

热门阅读

  1. C语言-整数与浮点数:内存存储的差异

    2024-03-23 06:14:04       21 阅读
  2. C#面:什么是不可变字符串

    2024-03-23 06:14:04       15 阅读
  3. GO 语言基础学习记录

    2024-03-23 06:14:04       22 阅读
  4. pytorch中的gather函数的定义和作用是什么?

    2024-03-23 06:14:04       21 阅读
  5. golang学习网址

    2024-03-23 06:14:04       20 阅读
  6. 【Go语言Decoder报错gob: duplicate type received】

    2024-03-23 06:14:04       19 阅读
  7. 【C++】Digit sum 2

    2024-03-23 06:14:04       17 阅读
  8. macOS - 创建聚合设备、切换声卡

    2024-03-23 06:14:04       17 阅读
  9. 数列特征

    2024-03-23 06:14:04       20 阅读
  10. Git学习笔记之Git 别名

    2024-03-23 06:14:04       18 阅读
  11. RK3568基于openHarmony3.2版本之GT911触摸屏调试成功

    2024-03-23 06:14:04       42 阅读
  12. OpenCV基于边缘的分割详解

    2024-03-23 06:14:04       18 阅读
  13. npm常用命令

    2024-03-23 06:14:04       21 阅读
  14. Kafka批量消费

    2024-03-23 06:14:04       20 阅读