Click here to Skip to main content
15,885,537 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more: , +
Hello all,

When my site is deployed and multiple people as using it I am trying to understand if my server were able to handle these requests from multiple people. At first itll only be 10-20 people but I plan on it growing. On the UI since its front end do the websockets open from from the client’s side and not on my server. Then on the API if it would be as many users that are logged in if they will each have their own websocket stream open to my server?
In addition, I was wondering this, if I had the exchange websocket open just 1 of them if it was on my server could I have every user just use that 1 stream and not need multiple of them?
I have never built a site using websockets before so I am not sure the right path to take. Am I thinking of this the right way or should both socket connections be opened on the client end and them it wouldn’t use much if not any of my server resources for that connection.

I am currently just using normal Websockets from javascript and c#.

Any input here would be greatly appreciated.
Thank you all.

What I have tried:

I been trying to grasp how this works and been doing research but still I do not have a full understanding. I have a trading bot that I am creating. It has an api that creates Trades on an exchange. I have a UI that shows everything. Currently I have 2 separate websocket connections. 1 for all the incoming trades from the exchange. This is on the UI. The 2nd is the users current trades as they update or change status, this one is currently on the API and it sends an httpclient to the UI as they occur which is a lot less frequently because it’s the users specific trades.

C#
  function updateState() {
            if (!socket) {

            } else {
                switch (socket.readyState) {
                    case WebSocket.CLOSED:
                        stateLabel.innerHTML = "Closed";
                        // disable();
                        connectionUrl.disabled = false;
                        connectButton.disabled = false;
                        break;
                    case WebSocket.CLOSING:
                        stateLabel.innerHTML = "Closing...";
                        //disable();
                        break;
                    case WebSocket.CONNECTING:
                        stateLabel.innerHTML = "Connecting...";
                        // disable();
                        break;
                    case WebSocket.OPEN:
                        stateLabel.innerHTML = "Open";
                        //enable();
                        break;
                    default:
                        stateLabel.innerHTML = "Unknown WebSocket State: " + socket.readyState;
                        //disable();
                        break;
                }
            }
        }

        connectButton.onclick = function () {
            stateLabel.innerHTML = "Connecting...";
            socket = new WebSocket(connectionUrl.value);
            socket.onopen = function (event) {
                $.ajax({
                    url: '@Url.Action("WebSocketsCacheOn", "Home")',
                    type: "GET",
                    dataType: "JSON",
                }).done(function (e) {
                   // alert('websaockets on');
                    @*$.ajax({
                        url: '@Url.Action("CaptureUserTradeData", "Home")',
                        type: "GET",
                    });*@
                    $('#connectButton').addClass('btn-success');
                    $('#connectButton').removeClass('btn-secondary');

                })
                stateLabel.innerHTML = "Connected";
            }

            socket.onclose = function (event) {
                stateLabel.innerHTML = "Closing...";

                //$("#divadd").innerHTML += "Closed";
                stateLabel.innerHTML = "Closed.";
                $('#connectButton').removeClass('btn-success');
                $('#connectButton').addClass('btn-secondary');
            };

            socket.onerror = function (e) {
                $("#divadd").innerHTML += "Errored";
            };

            socket.onmessage = function (event) {
                //$("#divadd").innerHTML += "event.data.p";
                var obj = JSON.parse(event.data.replace('\\', ''));
                var trade = event.data.replace('\\', '');

                $("#divadd").html += "<p>" + obj.p + "</p>";
                //$('#lstBox').innerHTML += "<option>" + obj.p + "</option>";
               // $("#divadd").insertAfter += "<span>" + obj.p + "</span>";
                updatePrice(obj);
                addData(obj);

                if (activeTrades) {
                    executeTradeAsync();

                }
                // Display Trade Below
                //updateTrade(trade);

                // Display Active Trades
                //updateActiveTrades();
            }
        };

Startup.cs
 app.UseWebSockets();
            // WebSockets Connection
            var webSocketOptions = new WebSocketOptions()
            {
                KeepAliveInterval = TimeSpan.FromSeconds(120),
            };
            app.UseWebSockets(webSocketOptions);
            app.Use(async (context, next) =>
            {
                if (context.Request.Path == "/ws")
                {
                    if (context.WebSockets.IsWebSocketRequest)
                    {
                        WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
                        await Echo(context, webSocket);
                    }
                    else
                    {
                        context.Response.StatusCode = 400;
                    }
                }
                else
                {
                    await next();
                }
            });
            async Task Echo(HttpContext context, WebSocket webSocket)
            {
                var buffer = new byte[1024 * 4];
                WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer),
                    CancellationToken.None);

                while (!result.CloseStatus.HasValue)
                {
                    await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType,
                    result.EndOfMessage, CancellationToken.None);
                    result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                    Console.WriteLine(result);
                }
                await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription,
                CancellationToken.None);
            }
Posted
Updated 24-May-21 6:35am
Comments
Greg Utas 24-May-21 12:41pm    
Be careful that your bot doesn't blow up your account or generate tons of transaction fees. I have lots of software experience but would be very wary of writing such an animal outside of a team setting where it could be rigorously tested before getting deployed. If I did write one, its trades would have to be manually approved until I knew that it wasn't psychotic, and even then I'd live in fear. Not to mention that such a bot probably relies heavily on TA and backtesting, which I think are largely horseshite. But that's a whole other topic. :)
TheBigBearNow 24-May-21 17:47pm    
I created a bot in WPF and at first I had the exact issues that you say here. Once I learned about semaphoreslims then I was able to successfully run this bot without any issues. Now I am working on creating this as a website so other people can use it. If I were to give people my WPF app they could steal my source code. That is why I am going web, the same idea and same stuff I had working but now I want user accounts to be able to use this separately.

1 solution

Asynchronous Server Socket Example | Microsoft Docs[^]

The above might help you out, it depends on how you've implemented your accept/receive endpoints. In theory your socket should be handling connections and reception of buffers on a separate thread to the UI thread.

The idea of the BeginAccept() and BeginReceive() C# methods is that they run asynchronously to your application, on a separate thread. Using these methods you can support as many connections as you need without blocking your UI or preventing other connections. This would be implemented on the server side.
 
Share this answer
 
Comments
TheBigBearNow 24-May-21 17:45pm    
Does this work with .net core web applications ?
This is a website I am creating.
Chris Copeland 25-May-21 4:18am    
If you look at the documentation page for BeginAccept you can see at the bottom it says the method is available on .NET Core 2.0, 2.1, 2.2, 3.0, 3.1. You can always check Microsoft's documentation for things like that.
TheBigBearNow 25-May-21 9:38am    
If I use my websockets with c# if there a way I could update a partial view from the controller. Display results that come from the websocket data? I know with javascript this can easily be done but i dont know how to do it with c# in the controller side of things
Chris Copeland 25-May-21 10:14am    
I'm not sure how that would work, are you saying that if server receives data then it should automatically present that data back the next time the view is rendered? If so, you're heading into database territory where you'll need to store things in a database to retrieve again the next time the view is being rendered.

This sort of sounds like how a "chat" system would work, where messages being sent over sockets land immediately on the page, but when the page is refreshed you would need to retrieve those messages back from a database to display them again when the page loads.
TheBigBearNow 28-May-21 11:14am    
Kind of.. I currently have websocket data being displayed on a page in real time with the JS .load() function. My .load() is refreshing a partial view. Currently I have data on a stream from an API coming in on a C# method. I was wondering if there is a same way to do this with c# (refresh a partial view) without using javascript .load or if I could somehow call my front end from my controller

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900