C# WebSocket实作双向通讯

本文将透过WebSocketSharp来实作WebSocket

Client使用js
Server使用C# .net 4.6.2

Step 1 下载NuGet套件
工具->NuGet套件管理员->管理方案的NuGet套件
https://ithelp.ithome.com.tw/upload/images/20210512/20110063oy9iCSA6ZG.png

Step2 撰写Server程序
(1) Global.设定监听port与连线Url
new WebSocketServer()可以设定监听port与Url、加密连线

public class WebApiApplication : HttpApplication
{
    public static WebSocketServer WebSocketServer { get; private set; }

    protected void Application_Start()
    {
        GlobalConfiguration.Configure(WebApiConfig.Register);

        WebSocketServer = new WebSocketServer(5000);
        WebSocketServer.AddWebSocketService<NotifyBehavior>("/notify");
        WebSocketServer.Start();
    }
}

(2) 新增Behavior

public class NotifyBehavior : WebSocketBehavior
{
    protected override void OnOpen()
    {
        //传送讯息至Client
        Send(JsonConvert.SerializeObject(new { message = "Open" }));
    }

    protected override void OnMessage(MessageEventArgs e)
    {
        //接收Client传入的讯息
        string msg = e.Data;
    }

    protected override void OnClose(CloseEventArgs e)
    {
        
    }

    protected override void OnError(ErrorEventArgs e)
    {
        
    }
}

Step 3 撰写Client程序

 <script>
        let wsc;
        (function () {
            if ("WebSocket" in window) {
                wsc = new WebSocket("ws://localhost:5000/notify");

                wsc.onopen = function () {
                    console.log("connected");
                    //传送讯息至Server
                    wsc.send('Client Connected.');
                };
                wsc.onclose = function () {
                    console.log("closed");
                };
                wsc.onmessage = function (e) {
                    //接收Server传入的讯息
                    var data = JSON.parse(e.data);
                    console.log(data.message);
                };
            }
        })();
    </script>

Step 4 Demo
Client可接收Server传送的讯息"Open"
https://ithelp.ithome.com.tw/upload/images/20210613/20110063ZWvKiUDvoR.png
Server可接收Client传送的讯息"Client Connected."
https://ithelp.ithome.com.tw/upload/images/20210613/20110063qpIHLEAEYl.png

程序码: https://github.com/jing-yu-wang/WebSocket


同场加映 使用wss连接
Server
path、pwd放站台凭证的路径与密码

WebSocketServer = new WebSocketServer(5000), true);
WebSocketServer.SslConfiguration.ServerCertificate = new X509Certificate2(path, pwd);

Client
将ws改为wss即可

wsc = new WebSocket("wss://localhost:5000/notify");

使用wss连线时遇到Client无法连线至Server的状况
failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
後来发现是要指定Tls1.2 连线

WebSocketServer.SslConfiguration.EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls12;

遇到的问题
站台回收後无法连线
将WebSocket Server架在IIS站台,站台回收後要将应用程序集区重新唤醒,才可以重新连线
(Web API、MVC网站架在IIS不会遇到这个问题,因为在第一个连线进来Request会自动将应用程序集区唤醒)

目前的解法:

  1. 设定Windows排程,每日固定时间执行以下cmd指令唤醒站台

powershell -Command "Invoke-WebRequest {站台Url} "

  1. WebSocket Server安装在Windows Service(尚未尝试)
    这个解法尚未尝试,但我认为应该可以避免掉站台回收的机制

结论
本文仅实作简单的连线与传送讯息,WebSocketSharp还包含其他功能,像是对所有Client广播、Server关闭特定Client的连线、握手请求中以QueryString的方式传送参数等等,github网站都有详细的说明与用法。

文章中有错误的地方,还请各位前辈不吝指教


<<:  IPv6 路由问题

>>:  资安入门

Day 29 |> Elixir 并行性 (三)

Agent Agent 模组提供了我们可以实践一个基本的服务器的一个 API 的功能。 可以让我们在...

Day10 React Props

此用React的最大目的就是将UI分区模组化成独立的、可复用的元件。 该如何运用这些元件? 就是将资...

Vue.js 从零开始 mitt

还记得区域元件有自己的作用域吗?已知外层元件可以跟内层元件传递资料(props),或是传递事件(em...

冒险村30 - Handle API response with value objects

30 - Handle API response with value objects 本篇将介绍撰...

Day30 完赛心得

很遗憾在第21天时没能来得及完成文章,虽然铁人赛中断了,後续还是努力完成30篇的篇幅,自己至少有在铁...