通用Websocket客户端组件,适用于C#,VB.net与VB6 的开发使用,支持WSS

近期由于业务需要,需要与视频会议服务器整合开发,由于会议服务器的控制方式要求采用Websocket方式,并且是WSS(加密Websocket协议), 由于一直采用VB6、VB.Net开发,因此就在网上搜索是否有合适的解决方案,花了两天时间都没有找到合适的。虽然笔者找到一些实现方案,但是要么就是VB实现的,不支持WSS,要么就是C#实现的,不支持VB开发,要么不支持64位Windows程序调用,反正没有找到合适的。因此不得不让笔者花时间来自己实现一个。
笔者,完全按照H5的Websocket对象实现了一个Websocket组件,用于支持VB6、VB.Net与C#等程序语言调用、支持原生64位与32位实现、支持OpenSSL实现安全套接字的WSS协议。Websocket代码完全采用C/C++实现,Socket I/O采用异步高性能调用方式。
Websocket组件完全参照H5的Websocket实现方式,具备的方法、属性与事件如下:
组件名称:VBToolsLib.Websocket,采用Com方式实现,同时编译成x86与x64版本
以编译的动态库形式发布,需要执行Regsvr32程序来注册这个COM组件,在64位操作系统下建议两个版本都注册。
该组件完全永久免费使用,没有任何功能限制,也没有时间限制,确保不含任何失效时间或者远程下发关闭的后门,可以长期永久免费无任何限制地使用。由于实现源码逻辑复杂,编译复杂,所以不提供组件的实现源码,省得麻烦。如有部分定制需求,可在评论区发言,笔者酌情修补。
VB,VB.NET, C# 都需要添加引用,引用的组件库名为:VBToolsLib,如下图所示:
在这里插入图片描述
可以在github里下载这个组件:
https://github.com/wenshui2008/WebsocketVB

VBToolsLib.WebSocket 组件属性

属性名称说明
readyState

只读属性 readyState 表示连接状态,以下值:

0 - 表示连接尚未建立。
1 - 表示连接已建立,可以进行通信。
2 - 表示连接正在进行关闭。
3 - 表示连接已经关闭或者连接不能打开。
bufferedAmount只读属性 bufferedAmount 已被 send() 放入正在队列中等待传输,但是还没有发出的 UTF-8 文本消息条数。每调用一次send,就会在组件的队列里添加一条消息,如果网速不足够快消息不一定会立即发送出去,需要排队等待。

VBToolsLib.WebSocket 组件方法

方法名称方法说明
open(sUrl)建立连接,输入的sUrl为Websocket的服务地址,例如:ws://192.168.1.200:3000、wss://192.168.1.200:3000
send(msg)使用连接发送数据,msg为要发送的文本字符串
close关闭连接
setwindowhandle64(hwnd)一个窗口句柄,Win32的HWND类型的句柄,C#与VB.Net的form的Handle,VB6的Form的 hWnd,为什么要增加这个方法呢,因为组件采用多线程方式,用单独的线程来处理网络I/O,这个方法就是用来让组件关联主线程、并在主线程上进行事件回调的。这个方法是H5的Websocket对象没有的。
setHttpHeader(name, value)设置http请求头字段,如果输入的请求头字段不存在,则添加一个;如果存在,则替换存在的头。在open方法调用前此方法设置的头可以有效,否则只能在close调用后重新调用open方法才能有效。这个方法是H5的Websocket对象没有的。
例如:setHttpHeader(“My-Header”,“Some Value”)

VBToolsLib.WebSocket 支持的事件

事件名称事件说明
onopen连接成功建立时触发
onmessage(data)客户端接收到服务端消息数据时触发
onerror(errmsg)通信发生错误时触发
onclose连接关闭时触发

以下是各种语言调用的样本代码,非常简单,现在一一介绍。

VB.Net方式

1)在Form的Load事件创建组件,并设置主窗口句柄,调用setwindowhandle64来设置窗口句柄,setwindowhandle为32位版本
2)在Form的Close事件里,注销与窗口句柄的关联,这步不是必须
3)实现接收组件的事件回调方法,websock_onopen、websock_onmessage、websock_onclose与websock_onerror等事件,
4)调用send发送消息,调用close关闭连接

Public Class mainForm
    Dim WithEvents websock As VBToolsLib.Websocket

    Delegate Sub appendText(s As String)
    Dim useSetwindowhandle As Boolean = False


    Private Sub mainForm_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        Dim count As Integer

        'TextBox.CheckForIllegalCrossThreadCalls = False
        '在窗口的初始化事件里创建Websocket对象
        websock = New VBToolsLib.Websocket

        '接着关联一个主线程窗口句柄便于接收Websocket消息
        'setwindowhandle方法用于设置关联窗口句柄(仅用于32位版本),setwindowhandle64为64位版本
        '仅需要调用这两个方法中的一个即可,64位版本必须用setwindowhandle64方法
        'websock.setwindowhandle(Me.Handle)
        'setwindowhandle64 即能够用于Windows 32位又能用于64位
        websock.setwindowhandle64(Me.Handle)
        '因为调用了setwindowhandle64方法,所以设置标志为True
        useSetwindowhandle = True
        '任何时间都可以调用bufferedAmount属性获取尚未发送的缓冲数目,这里仅是演示
        count = websock.bufferedAmount
		'在调用open 方法之前可以设置Http 请求头,这些头放在标准的HTTP协议请求头里发送给服务器
        websock.setHttpHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36")
        websock.setHttpHeader("Cookie", "XMPlayer=V1.0; PHPSESSID=3nm364h6bu2i80lp4esik5ki56")

        urlInput.Text = "wss://192.168.2.134:3000/"

        If (IntPtr.Size = 8) Then
            Me.Text &= " (x64)"
        End If
    End Sub

    Private Sub mainForm_FormClosed(sender As System.Object, e As System.Windows.Forms.FormClosedEventArgs) Handles MyBase.FormClosed
        '在窗口关闭事件里取消窗口句柄关联,不是必须
        If useSetwindowhandle Then
            websock.setwindowhandle(0)
        End If
    End Sub

    Private Sub OpenBtn_Click(sender As System.Object, e As System.EventArgs) Handles OpenBtn.Click
        Dim url
        url = urlInput.Text

        If url <> "" Then
            '连接服务器,执行的是异步操作,只能通过监听onopen与onerror事件来判断是否成功
            websock.open(url)
        End If
    End Sub

    Private Sub CloseBtn_Click(sender As System.Object, e As System.EventArgs) Handles CloseBtn.Click
        websock.close()
    End Sub

    Private Sub SendBtn_Click(sender As System.Object, e As System.EventArgs) Handles SendBtn.Click
        Dim sMsg As String = msgInputBox.Text

        If sMsg <> "" Then
            websock.send(sMsg)
        End If
    End Sub

    Private Sub websock_onopen() Handles websock.onopen
        Dim sTime As String = DateDiff("s", "1970-01-01 00:00:00", Now)
        Dim sMsg = ""
        websock.send("login: " & sTime)

        sMsg = "OnOpen" & Chr(13) & Chr(10)
        If useSetwindowhandle Then
            msgListbox.AppendText(sMsg)
        Else
            '如果没有调用setwindowhandle关联窗体句柄,就必须用委托方式,否则可能会有多线程界面死锁问题
            Me.Invoke(New appendText(AddressOf AppendTextMethod), sMsg)
        End If
    End Sub

    Private Sub websock_onmessage(ByVal msg As String) Handles websock.onmessage
        Dim sMsg As String

        sMsg = msg & Chr(13) & Chr(10)
        If useSetwindowhandle Then
            msgListbox.AppendText(sMsg)
        Else
            '如果没有调用setwindowhandle(x64),就必须用委托方式,否则会有多线程界面死锁问题
            Me.Invoke(New appendText(AddressOf AppendTextMethod), sMsg)
        End If

        '这里演示处理消息,具体业务逻辑的实现可能不是这样的,这里仅为演示
        If (msg = "[MSG]:close") Then
            websock.close()
        ElseIf (msg.Substring(0, 14) = "[MSG]:foreward") Then
            Dim newmsg = msg.Substring(14)
            '演示将消息重新转发出去,具体业务逻辑由调用者自己实现,这里仅仅为演示
            websock.send("[MSG]:This is a foreward MSG:" & newmsg)
        End If
    End Sub

    Private Sub websock_onclose() Handles websock.onclose
        Dim sMsg As String
        sMsg = "Onclose" & Chr(13) & Chr(10)
        If useSetwindowhandle Then
            msgListbox.AppendText(sMsg)
        Else
            '没有调用setwindowhandle(x64),就必须用委托方式,否则有多线程问题
            Me.Invoke(New appendText(AddressOf AppendTextMethod), sMsg)
        End If
    End Sub

    Private Sub websock_onerror(ByVal msg As String) Handles websock.onerror
        Dim sMsg As String

        sMsg = "onerror:" & msg & Chr(13) & Chr(10)
        If useSetwindowhandle Then
            msgListbox.AppendText(sMsg)
        Else
            '调用了 setwindowhandle(x64) 就不用委托方式了,否则会有多线程问题
            Me.Invoke(New appendText(AddressOf AppendTextMethod), sMsg)
        End If
    End Sub

    Public Sub AppendTextMethod(msgText As String)
        msgListbox.AppendText(msgText)
    End Sub
End Class


用VB.NET实现的界面如下:
在这里插入图片描述

C#的实现代码

过程与VB.NET的过程完全一样。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace CSTester
{
    public partial class mainForm : Form
    {
        VBToolsLib.Websocket websock;

        public mainForm()
        {
            InitializeComponent();
        }

        private void mainForm_Load(object sender, EventArgs e)
        {
            int count;
            
            //在窗口的初始化事件里创建Websocket对象
            websock = new VBToolsLib.Websocket();

            //关联主线程句柄便于接收Websocket消息
            //setwindowhandle方法用于关联窗口句柄,setwindowhandle64为64位版本,调用其中一个即可
            //websock.setwindowhandle((int)this.Handle);
            websock.setwindowhandle64((long)this.Handle);
            
			// 在调用open 方法之前可以设置Http 请求头,这些头放在标准的HTTP协议请求头里发送给服务器
            websock.setHttpHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36");
            websock.setHttpHeader("Cookie", "XMPlayer=V1.0; PHPSESSID=3nm364h6bu2i80lp4esik5ki56");

            urlInput.Text = "wss://192.168.2.134:3000/";
            //演示获取属性
            count = websock.bufferedAmount;
            //C#方式的设置事件
            websock.onopen    += websocket_onopen;
            websock.onclose   += websocket_onclose;
            websock.onmessage += websocket_onmessage;
            websock.onerror   += websocket_onerror;

            if (IntPtr.Size == 8) {
                this.Text += " (x64)";
            }
        }

        private void mainForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            //在窗口关闭事件里取消窗口句柄关联,不是必须
            websock.setwindowhandle(0);
        }

        private void btnOpen_Click(object sender, EventArgs e)
        {
            string sUrl = urlInput.Text;

            if (sUrl != "") {
                websock.open(sUrl);
            }
        }

        private void btnClose_Click(object sender, EventArgs e)
        {
            websock.close();
        }
        
        private void btnSend_Click(object sender, EventArgs e)
        {
            string sMsg = msgInput.Text;

            if (sMsg != "")
            {
                websock.send(sMsg);
            }
        }

        private void websocket_onopen()
        {
            string sTime;
            string sMsg;

            TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0);

            sTime = Convert.ToInt64(ts.TotalSeconds).ToString();
            //这里演示给服务器发送一个消息,具体业务逻辑应该在服务器上实现
            websock.send("login: " + sTime);

            sMsg = "OnOpen\r\n";
            msgListbox.AppendText(sMsg);
        }

        private void websocket_onclose()
        {
            string sMsg;

            sMsg = "Onclose\r\n";

            msgListbox.AppendText(sMsg);
        }

        private void websocket_onmessage(string msg)
        {
            string sMsg;

            sMsg = msg + "\r\n";

            msgListbox.AppendText(sMsg);
            //这里演示处理消息,具体业务逻辑的实现可能不是这样的,这里仅为演示
            if (msg == "[MSG]:close")
            {
                websock.close();
            }
            else if (msg.Substring(0, 14) == "[MSG]:foreward")
            {
                string newmsg = msg.Substring(14);
                //演示将消息重新转发出去,具体业务逻辑由调用者自己实现,这里仅仅为演示
                websock.send("[MSG]:This is a foreward MSG:" + newmsg);
            }
        }

        private void websocket_onerror(string errmsg)
        {
            string sMsg;

            sMsg = "onerror:" + errmsg + "\r\n";

            msgListbox.AppendText(sMsg);
        }
    }
}

C#的界面如下:
在这里插入图片描述

VB6 调用的实现:

调用过程与以上一样,仅仅是VB6的代码不一样
VB6代码如下:

Dim WithEvents websock As VBToolsLib.Websocket
Private Sub Form_Load()
    Dim count As Integer
    
    Set websock = New VBToolsLib.Websocket
    '设置一个窗口关联句柄,VB6仅支持32位版本即可
    websock.setwindowhandle (Me.hWnd)
        
    count = websock.bufferedAmount
    '在调用open 方法之前可以设置Http 请求头,这些头放在标准的HTTP协议请求头里发送给服务器
    websock.setHttpHeader "User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; VB6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36"
    websock.setHttpHeader "Cookie", "XMPlayer=V1.0; PHPSESSID=3nm364h6bu2i80lp4esik5ki56"

    urlInput.Text = "wss://192.168.2.134:3000/"
End Sub

Private Sub Form_Unload(Cancel As Integer)
    websock.setwindowhandle (0)
End Sub

Private Sub btnOpen_Click()
    Dim url As String

    url = urlInput.Text

    If url <> "" Then
        websock.open (url)
    End If
End Sub

Private Sub btnClose_Click()
    websock.Close
End Sub

Private Sub btnSend_Click()
    Dim sMsg As String
    sMsg = msgInput.Text

    If sMsg <> "" Then
        websock.send (sMsg)
    End If
End Sub

Private Sub websock_onopen()
    Dim sTime As String
    Dim sMsg As String
    
    sTime = DateDiff("s", "1970-01-01 00:00:00", Now)
    '演示发送消息,具体业务逻辑由开发者自己实现,这里仅为演示代码
    websock.send ("login: " & sTime)

    sMsg = "OnOpen" & Chr(13) & Chr(10)
    msgListbox.Text = msgListbox.Text & sMsg

End Sub

Private Sub websock_onclose()
    Dim sMsg As String
    
    sMsg = "Onclose" & Chr(13) & Chr(10)
    msgListbox.Text = msgListbox.Text & sMsg
    
End Sub
Private Sub websock_onmessage(ByVal msg As String)
    
    Dim sMsg As String

    sMsg = msg & Chr(13) & Chr(10)
    msgListbox.Text = msgListbox.Text & sMsg
    '仅为演示处理消息,具体业务逻辑应该由开发者自己实现
    If (msg = "[MSG]:close") Then
       websock.Close
    ElseIf Mid(msg, 1, 14) = "[MSG]:foreward" Then
       Dim newmsg
       
       newmsg = Mid(msg, 15)

       websock.send ("[MSG]:This is a foreward MSG:" & newmsg)
    End If
End Sub

Private Sub websock_onerror(ByVal errmsg As String)
    Dim sMsg As String
    
    sMsg = "onerror:" & errmsg & Chr(13) & Chr(10)
    
    msgListbox.Text = msgListbox.Text & sMsg
End Sub

Public Sub AppendTextMethod(msgText As String)
    'msgListbox.AppendText (msgText)
End Sub
    

VB6的界面如下:

在这里插入图片描述
注意:由于VB6本身不支持64位代码,因此只能用32位的组件。

该组件用于VB/C#的Websocket服务器端代码暂时没有时间实现,后续再实现。

测试程序的全部源代码在这:
https://github.com/wenshui2008/WebsocketVB

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
HTML 5 Web Sockets is a powerful and effective technique for real-time information processing. There exists many techniques such as Poling, Long Poling and Streaming that are said to be better earier days. With web sockets, it shows a better outcome for the end user as well as a proper utilization of the server bandwidth. WebSocket is a web technology providing full-duplex communications channels over a single TCP connection. The WebSocket protocol was standardized by the IETF as RFC 6455 in 2011, and the WebSocket API for in Web IDL is being standardized by the W3C.WebSocket is designed to be implemented in web browsers and web servers, but it can be used by any client or server application. The WebSocket Protocol is an independent TCP-based protocol. Its only relationship to HTTP is that its handshake is interpreted by HTTP servers as an Upgrade request. The WebSocket protocol makes possible more interaction between a browser and a web site, facilitating live content and the creation of real-time games. This is made possible by providing a standardized way for the server to send content to the browser without being solicited by the client, and allowing for messages to be passed back and forth while keeping the connection open. In this way a two-way (bi-directional) ongoing conversation can take place between a browser and the server. A similar effect has been achieved in non-standardized ways using stop-gap technologies such as Comet.In addition, the communications are done over TCP port number 80, which is of benefit for those environments which block non-standard Internet connections using a firewall. WebSocket protocol is currently supported in several browsers including Google Chrome, Internet Explorer, Firefox, Safari and Opera. WebSocket also requires web applications on the server to support it. Here goes a comparison of polling vs Web Sockets.
在Vue3 + Vite项目中使用WebSocket可以通过`WebSocket`对象来实现,WebSocket的地址需要填写后WebSocket服务地址。你可以在Vue的组件使用WebSocket对象,示例代码如下: ```javascript // 创建WebSocket对象,使用WebSocket服务地址 const socket = new WebSocket('ws://localhost:5000/ws'); // 监听WebSocket的打开事件 socket.addEventListener('open', (event) => { console.log('WebSocket已连接'); }); // 监听WebSocket的消息事件 socket.addEventListener('message', (event) => { console.log('接收到消息:', event.data); }); // 监听WebSocket的关闭事件 socket.addEventListener('close', (event) => { console.log('WebSocket已关闭'); }); // 发送消息 socket.send('Hello WebSocket!'); ``` 在C# asp.net core后中,可以使用`Microsoft.AspNetCore.WebSockets`包来实现WebSocket服务。示例代码如下: ```csharp // 添加WebSocket中间件 app.UseWebSockets(); // 注册WebSocket处理器 app.Use(async (context, next) => { if (context.WebSockets.IsWebSocketRequest) { WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync(); // 处理WebSocket消息 await HandleWebSocketAsync(webSocket); } else { await next(); } }); // 处理WebSocket消息的方法 async Task HandleWebSocketAsync(WebSocket webSocket) { byte[] buffer = new byte[1024 * 4]; WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None); while (!result.CloseStatus.HasValue) { // 处理WebSocket消息 string message = Encoding.UTF8.GetString(buffer, 0, result.Count); Console.WriteLine($"接收到消息:{message}"); // 发送WebSocket消息 byte[] messageBytes = Encoding.UTF8.GetBytes($"Echo: {message}"); await webSocket.SendAsync(new ArraySegment<byte>(messageBytes), WebSocketMessageType.Text, true, CancellationToken.None); // 继续接收WebSocket消息 result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None); } // 关闭WebSocket连接 await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None); } ``` 注意:在使用WebSocket时,需要确保后WebSocket服务地址正确,且前后WebSocket协议一致。例如,如果前使用的是`ws`协议,则后也需要使用`ws`协议;如果前使用的是`wss`协议,则后也需要使用`wss`协议。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值