Search code examples
c#arraysstringtcpswitch-statement

Switch statement strings matching but not functioning


I have a switch statement that uses a string converted from a char[] that was sent over a data stream from a server to the client. The code is client-side.

The default case is always hit even though the server and the default error code is always matching cases exactly.

SERVER SIDE
private void SendToClient(string message, TcpAccount account)
    {
        try
        {
            byte[] buffMessage = Encoding.ASCII.GetBytes(message);
            account.TcpClient.GetStream().WriteAsync(buffMessage, 0, buffMessage.Length);
            log.AppendText(string.Format("Message {0} sent to account {1}", message, account.ID));
            log.AppendText(Environment.NewLine);
        }
        catch
        {
            log.AppendText(string.Format("Message {0} sent to account {1}", message, account.ID));
            log.AppendText(Environment.NewLine);
        }
    }

CLIENT SIDE
public async void ReadDataAsync(TcpClient client)
    {
        try
        {
            StreamReader clientStreamReader = new StreamReader(client.GetStream());
            char[] buff = new char[64];
            int readByteCount = 0;

            while (true)
            {
                readByteCount = await clientStreamReader.ReadAsync(buff, 0, buff.Length);

                if (readByteCount <= 0)
                {
                    Console.WriteLine("Disconnected from server.");
                    client.Close();
                    break;
                }
                string code = new string(buff);
                ProcessServerCode(code);
                Array.Clear(buff, 0, buff.Length);
            }
        }
        catch
        {

        }
    }

public void ProcessServerCode(string code)
    {
        switch (code)
        {
            case "regcom":
                MessageBox.Show("Registration Complete");
                break;

            case "logcom":
                MessageBox.Show("Login Complete");
                break;

            case "badpass":
                MessageBox.Show("Invalid Password");
                break;

            case "badaccount":
                MessageBox.Show("Invalid Account");
                break;

            default:
                MessageBox.Show("Unknown Code: " + code);
                break;
        }
    }

I can't get it off the default code.

Also, since I'm new to client/server and socket programming, I just realized the server sends a byte[] but the client receives a char[]. Is there any conflict there? Any particular reason for this (since I'm using those particular pieces of code from an online training session)?


Solution

  • The first problem I see is that you're ignoring readByteCount (which is actually a character count, not a byte count); you should use:

    string code = new string(buff, 0, readByteCount);
    

    However, the next problem I see is that you don't have any framing protocol. This means:

    • if two messages are sent close together, you could receive what appears to be a single concatenated value
    • even individual values could be arbitrarily truncated as they get split between packets
    • etc

    In either case:

    • if the message is longer than your buffer length, you're broken
    • if you ever receive more than one message at a time, you're broken

    as in either case, it'll never be possible to recover the position correctly. Hence: frames, where each frame is a complete message.

    A common approach with text-based protocols is to use a newline as a frame (I'll let you decide whether that means CR, LF, CRLF, etc); then you can just use ReadLine / ReadLineAsync on the text reader, and it'll do it all automatically, so:

    string code = await clientStreamReader.ReadLineAsync();
    if (code is null)
    {
        Console.WriteLine("Disconnected from server.");
        client.Close();
    }
    else
    {
        ProcessServerCode(code);
    }