1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
<script lang="javascript"> var ConnectionString = "ws://" + location.host + "/Handler1.ashx"; //http://localhost:1981/Handler1.ashx console.log(ConnectionString); let socket = new WebSocket(ConnectionString); //, "protocolOne" socket.onopen = function(e) { document.body.innerHTML +=("[open] Connection established"); document.body.innerHTML +=("Sending to server"); socket.send("My name is John"); }; socket.onmessage = function(event) { document.body.innerHTML += (`[message] Data received from server: ${event.data}`); }; socket.onclose = function(event) { if (event.wasClean) { document.body.innerHTML += (`[close] Connection closed cleanly, code=${event.code} reason=${event.reason}`); } else { // e.g. server process killed or network down // event.code is usually 1006 in this case document.body.innerHTML += ('[close] Connection died'); } }; socket.onerror = function(error) { document.body.innerHTML += (`[error] ${error.message}`); }; </script> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
Imports System.Net.WebSockets Imports System.Threading Imports System.Threading.Tasks Imports System.Web Imports System.Web.Services Public Class Handler1 Implements System.Web.IHttpHandler Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest 'context.Response.ContentType = "text/plain" 'context.Response.Write("Hello World!") If (context.IsWebSocketRequest) Then context.AcceptWebSocketRequest(AddressOf HandleWebSocket) Else context.Response.StatusCode = 400 End If End Sub Private Async Function HandleWebSocket(ByVal wsContext As WebSocketContext) As Task Const maxMessageSize As Integer = 1024 Dim receiveBuffer As Byte() = New Byte(1023) {} Dim socket As WebSocket = wsContext.WebSocket Global_asax.WebSocketsConnected.Add(socket) While socket.State = WebSocketState.Open Dim receiveResult As WebSocketReceiveResult = Await socket.ReceiveAsync(New ArraySegment(Of Byte)(receiveBuffer), CancellationToken.None) If receiveResult.MessageType = WebSocketMessageType.Close Then Await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, String.Empty, CancellationToken.None) ElseIf receiveResult.MessageType = WebSocketMessageType.Binary Then Await socket.CloseAsync(WebSocketCloseStatus.InvalidMessageType, "Cannot accept binary frame", CancellationToken.None) Else Dim count As Integer = receiveResult.Count While receiveResult.EndOfMessage = False If count >= maxMessageSize Then Dim closeMessage As String = String.Format("Maximum message size: {0} bytes.", maxMessageSize) Await socket.CloseAsync(WebSocketCloseStatus.MessageTooBig, closeMessage, CancellationToken.None) Return End If receiveResult = Await socket.ReceiveAsync(New ArraySegment(Of Byte)(receiveBuffer, count, maxMessageSize - count), CancellationToken.None) count += receiveResult.Count End While Dim receivedString = Encoding.UTF8.GetString(receiveBuffer, 0, count) Dim echoString = "You said " & receivedString Dim outputBuffer As ArraySegment(Of Byte) = New ArraySegment(Of Byte)(Encoding.UTF8.GetBytes(echoString)) Await socket.SendAsync(outputBuffer, WebSocketMessageType.Text, True, CancellationToken.None) End If End While End Function ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable Get Return False End Get End Property End Class |
Add this line to allow current connections to be accessed.
1 2 3 4 5 6 7 8 9 10 11 12 |
Imports System.Net.WebSockets Imports System.Web.Optimization Public Class Global_asax Inherits HttpApplication Public Shared WebSocketsConnected As New List(Of WebSocket) '<--Add this Sub Application_Start(sender As Object, e As EventArgs) ' Fires when the application is started RouteConfig.RegisterRoutes(RouteTable.Routes) BundleConfig.RegisterBundles(BundleTable.Bundles) End Sub End Class |
Send data from another event to trigger to all connected websockets
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Public Class Contact Inherits Page Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load Dim Message As String = "Hello!!" Dim outputBuffer As ArraySegment(Of Byte) = New ArraySegment(Of Byte)(Encoding.UTF8.GetBytes(Message)) For Each MySocket As Net.WebSockets.WebSocket In Global_asax.WebSocketsConnected If MySocket.State = Net.WebSockets.WebSocketState.Open Then MySocket.SendAsync(outputBuffer, Net.WebSockets.WebSocketMessageType.Text, True, Threading.CancellationToken.None) End If Next End Sub End Class |
One last thing, you may also need to enable websockets if your on an older version of a project. Add or merge these params below into your system.web tag
1 |
<httpRuntime executionTimeout="300" targetFramework="4.7.2" /> |
And below is a sample of a test client form to use on Desktop machines to communicate with the server if needed, just update the URL to point to your source.
one thing to note, is when dealing with Websockets in this way you must avoid using .Wait on the main thread to prevent deadlocks. When the function itself is called it will halt on the first await command and never return. I think this is because the report data is being processed through the main message pump of the main thread and gets locked by using the wait() command. Its best to check the status in a loop with application.doevents and add a sleep if needed.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
Imports System.Net Imports System.Net.WebSockets Imports System.Text Imports System.Threading Public Class Form1 Const maxMessageSize As Integer = 1024 Dim receiveBuffer As Byte() = New Byte(1023) {} Dim MySockets As New List(Of System.Net.WebSockets.ClientWebSocket) Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load Dim socket As New System.Net.WebSockets.ClientWebSocket MySockets.Add(socket) Dim result As Task(Of Boolean) = myTask(socket) Exit Sub While result.Status <> TaskStatus.RanToCompletion Application.DoEvents() End While Debug.WriteLine(result.Status & " result: " & result.Result) ' "WaitingForActivation" Exit Sub ThisTest() Exit Sub End Sub Public Async Sub ThisTest() Dim ws = New System.Net.WebSockets.ClientWebSocket ' optional: ignore certificate errors Net.ServicePointManager.ServerCertificateValidationCallback = Function(s, c, h, d) True Try Await ws.ConnectAsync(New Uri("wss://demo.piesocket.com/v3/channel_1?api_key=oCdCMcMPQpbvNjUIzqtvF1d2X2okWpDQj4AwARJuAgtjhzKxVEjQU6IdCjwm¬ify_self"), Nothing) If (ws.State = WebSockets.WebSocketState.Open) Then Debug.Print("Opened.") Await ws.SendAsync(New ArraySegment(Of Byte)(System.Text.Encoding.UTF8.GetBytes("{ ""message"":""hello""}")), WebSockets.WebSocketMessageType.Text, True, Nothing) Dim bytes(4096) As Byte Dim answ = New ArraySegment(Of Byte)(bytes) Await ws.ReceiveAsync(answ, Nothing) Debug.Print("answer:" + System.Text.Encoding.UTF8.GetString(answ.Array)) Else Debug.Print("Not opened?!") End If Catch Debug.Print("Error.") End Try End Sub Private Async Function myTask(socket As System.Net.WebSockets.ClientWebSocket) As Task(Of Boolean) Dim myToken As New CancellationTokenSource(5000) Net.ServicePointManager.ServerCertificateValidationCallback = Function(s, c, h, d) True Await socket.ConnectAsync(New Uri("wss://demo.piesocket.com/v3/channel_1?api_key=oCdCMcMPQpbvNjUIzqtvF1d2X2okWpDQj4AwARJuAgtjhzKxVEjQU6IdCjwm¬ify_self"), myToken.Token) While Not socket.State = WebSocketState.Open Application.DoEvents() End While Dim count As Integer = 0 While socket.State = WebSocketState.Open Dim receiveResult As WebSocketReceiveResult = Await socket.ReceiveAsync(New ArraySegment(Of Byte)(receiveBuffer, 0, receiveBuffer.Length - 1), CancellationToken.None) Dim receivedString = Encoding.UTF8.GetString(receiveBuffer, 0, count) Dim echoString = "You said " & receivedString Dim outputBuffer As ArraySegment(Of Byte) = New ArraySegment(Of Byte)(Encoding.UTF8.GetBytes(echoString)) 'Await socket.SendAsync(outputBuffer, WebSocketMessageType.Text, True, CancellationToken.None) 'Debug.WriteLine("I Recv: " & System.Text.ASCIIEncoding.ASCII.GetString(receiveBuffer)) If receiveResult.MessageType = WebSocketMessageType.Close Then Await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, String.Empty, CancellationToken.None) ElseIf receiveResult.MessageType = WebSocketMessageType.Binary Then Await socket.CloseAsync(WebSocketCloseStatus.InvalidMessageType, "Cannot accept binary frame", CancellationToken.None) Else count = receiveResult.Count While receiveResult.EndOfMessage = False If count >= maxMessageSize Then Dim closeMessage As String = String.Format("Maximum message size: {0} bytes.", maxMessageSize) Await socket.CloseAsync(WebSocketCloseStatus.MessageTooBig, closeMessage, CancellationToken.None) Return False End If receiveResult = Await socket.ReceiveAsync(New ArraySegment(Of Byte)(receiveBuffer, count, maxMessageSize - count), CancellationToken.None) count += receiveResult.Count End While Debug.WriteLine("I Recv: " & System.Text.ASCIIEncoding.ASCII.GetString(receiveBuffer)) End If End While Return False End Function Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click For Each MySocket As ClientWebSocket In MySockets If MySocket.State = WebSocketState.Open Then Dim outputBuffer As ArraySegment(Of Byte) = New ArraySegment(Of Byte)(Encoding.UTF8.GetBytes("Got it!" & Now.TimeOfDay.ToString)) Debug.WriteLine("I Recv: " & System.Text.ASCIIEncoding.ASCII.GetString(receiveBuffer)) Await MySocket.SendAsync(outputBuffer, WebSocketMessageType.Text, True, CancellationToken.None) End If Next End Sub End Class |
Other useful links on this topic I found:
https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_server
https://www.esegece.com/websockets/main-components/net-components/net-websocket-client
https://mcguirev10.com/2019/08/17/how-to-close-websocket-correctly.html
Use this if you’d like to connect with powershell!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
Try{ Do{ $URL = 'ws://YourDOmain.com/WebSocketHandler.ashx' $WS = New-Object System.Net.WebSockets.ClientWebSocket $CT = New-Object System.Threading.CancellationToken $WS.Options.UseDefaultCredentials = $true #Get connected $Conn = $WS.ConnectAsync($URL, $CT) While (!$Conn.IsCompleted) { Start-Sleep -Milliseconds 100 } Write-Host "Connected to $($URL)" $Size = 1024 $Array = [byte[]] @(,0) * $Size #Send Starting Request $Command = [System.Text.Encoding]::UTF8.GetBytes("ACTION=Command") $Send = New-Object System.ArraySegment[byte] -ArgumentList @(,$Command) $Conn = $WS.SendAsync($Send, [System.Net.WebSockets.WebSocketMessageType]::Text, $true, $CT) While (!$Conn.IsCompleted) { #Write-Host "Sleeping for 100 ms" Start-Sleep -Milliseconds 100 } Write-Host "Finished Sending Request" #Start reading the received items While ($WS.State -eq 'Open') { $Recv = New-Object System.ArraySegment[byte] -ArgumentList @(,$Array) $Conn = $WS.ReceiveAsync($Recv, $CT) While (!$Conn.IsCompleted) { #Write-Host "Sleeping for 100 ms" Start-Sleep -Milliseconds 100 } #Write-Host "Finished Receiving Request" [System.Text.Encoding]::utf8.GetString($Recv.array) } } Until ($WS.State -ne 'Open') }Finally{ If ($WS) { Write-Host "Closing websocket" $WS.Dispose() } } |