0

I have a Signalr web app that is using sockets to interact with a server application I can't control (nore have a source code / a protocol for). Each Signalr client sends a command to a Signalr Hub which sends opens a socket, sends a command to the server app then gets one or more responses back, which get sent back to the signalr client.

What I'm finding is that periodically (not clear on why) the server app stops sending responses back to the Signalr Hub. It does this when deployed and also when debugging locally. I'm creating a new Socket connection for each client command and closing it once we've received everything from the server app.

Stopping and starting the web app always fixes this, however given I'm not reusing socket connections I'm really not sure what's making this fix work. My thinking is that if I can understand that I can fix the cause.

public async Task SendCommand(string device, string? command)
{
        var ipendPoint = new IPEndPoint(ipaddress, port);
        var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
        {
            ReceiveTimeout = (int)TimeSpan.FromSeconds(5).TotalMilliseconds,
            SendTimeout = (int)TimeSpan.FromSeconds(30).TotalMilliseconds,
        };
        await socket.ConnectAsync(ipendPoint);

        try
        {
            while (true)
            {
                string? response = await SendCommandToServerAsync(socket, ipendPoint, device, command);
                command = null;
                if (response == null)
                {
                    await Task.Delay(2000);
                    continue;
                }

                if (response.Trim() != "GET&")
                { // If we're only sent a 'get' then don't update the client since there's no prompt
                    var parsedResponse = ParseResponse(response);
                    await Clients.Group(device).SendAsync("ReceiveResponse", device, parsedResponse);
                }

                if (response.Trim().EndsWith("GET&"))
                {
                    break;
                }

                await Task.Delay(2000);
            }
        }
        finally
        {
            if (socket.Connected)
            {
                socket.Close();
            }
        }
}

private async Task<string?> SendCommandToServerAsync(Socket socket, IPEndPoint ipendPoint, string device, string? command)
{
    var responseSB = new StringBuilder();
    var debugSB = new StringBuilder();

    var text = device + "&" + command?.ToUpper() + "\r\n";
    var bRequest = Encoding.UTF8.GetBytes(text.ToString());

    debugSB.Append("request: " + text);

    string? result;
    try
    {
        if (command != null)
        {
            debugSB.AppendLine("Sent request");
            await socket.SendAsync(bRequest);
        }
        else
        {
            debugSB.AppendLine("Command is null");

        }
        await Task.Delay(900);
        byte[] array = new byte[8192];
        int num2 = 0;
        string text2;
        while (true)
        {
            await Task.Delay(300);
            if (!socket.Connected)
            {
                debugSB.AppendLine("Socket not connected");
                socket.Connect(ipendPoint);
            }

            int num3 = await socket.ReceiveAsync(array, SocketFlags.None);
            debugSB.AppendLine("Received " + num3.ToString() + " bytes");
            num2++;
            if (num3 > 0)
            {
                text2 = Encoding.Default.GetString(array, 0, num3);
                responseSB.AppendLine("Received: " + text2);
                string text3 = text2;
                text3 = text3.Replace("BEEP&" + '�', "");
                if (!(text3 == "") && text2.IndexOf('�') >= 0)
                {
                    break;
                }
                else
                {
                    _emailSender.SendEmail("[email protected]", "AquaBar Info", "Got here with response: " + text2);
                }
            }
            else if (num2 == 20)
            {
                debugSB.AppendLine("Going to block_12");
                goto Block_12;
            }
        }

        debugSB.AppendLine("Out of while loop");

        string[] array2 = text2.Split(['�']);
        if (array2.Length > 2 && array2[0] == array2[1] && array2[0] != "BEEP&" && array2[0] != "PROMPT&")
        {
            text2 = array2[1];
        }
        return text2.Replace('�', ' ');
    Block_12:
        result = "Please Enter to Continue..GET&";

        _emailSender.SendEmail("[email protected]", "AquaBar Info", "Got to Please enter with response: " + responseSB.ToString() + Environment.NewLine + Environment.NewLine + "Debug: " + Environment.NewLine + debugSB.ToString());
    }
    catch (SocketException ex) when (ex.SocketErrorCode == SocketError.TimedOut)
    {
        result = null;
    }
    catch (IOException)
    {
        result = null;
    }
    catch (Exception)
    {
        result = "BEEP& ***Error***\n Server connection error.\n Please contact Administrator.";
    }
    return result;
}
13
  • How are you able to send multiple responses on the same request? A request normally only gets one response.
    – jdweng
    Commented Jul 8 at 7:52
  • Are you talking about a signalr response to the client, or are you talking about the servera app's response to my web app? If signalr I'm just sending multiple method calls to the client. If the server app, Are you saying that ReceiveAsync should only ever receive the entire response? My assumption was that sometimes a socket could receive some data, then receive some more data, if the server on the other end sent some data, waited then sent more data. Commented Jul 8 at 8:11
  • You appear to not have proper message framing. You may get part of a message in one read and part in another, you may get two messages in a single read. This is why you don't want to roll your own TCP messaging. Use an existing protocol such as HTTP to communicate with this server. Assuming you really do need to implement a full TCP protocol yourself, have a good read of blog.stephencleary.com/2009/04/tcpip-net-sockets-faq.html because there are many other pitfalls which you are not looking at: Nagle's algorithm/NoDelay, error handling, encoding, and what's with all those Task.Delay? Commented Jul 8 at 9:43
  • Read following : learn.microsoft.com/en-us/aspnet/signalr/overview/…
    – jdweng
    Commented Jul 8 at 9:43
  • Are you running IIS on windows professional? it has a limit of max 10 concurrent connections.
    – A Houghton
    Commented Jul 8 at 13:46

0

Browse other questions tagged or ask your own question.