Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

No Stream.ReadByteAsync?

I'm writing a game server using it's own protocol on top of TCP.
The packets are of the form varint packet_length followed by that amount of bytes.

To read a varint, I must read byte by byte. But Stream or NetworkStream does not provide a ReadByteAsync method, which means the task and therefore the thread will block if there is no data available from the socket yet. Of course I would wrap NetworkSteam with a BufferedStream but even BufferedStream's ReadByte uses synchronous Read to read to it's buffer. This will block.

This is how the server roughly looks like:

public static void Main(string[] args)
{
    var listener = new TcpListener(new IPEndPoint(IPAddress.Any, 25000));
    while (true)
    {
        var client = listener.AcceptTcpClientAsync().Result;
        HandleClient(client).ContinueWith(t => {
            if (t.IsFaulted)
            {
                Console.WriteLine(t.Exception);
            }
        });
    }
}

public static async Task HandleClient(TcpClient client)
{
    await Task.Yield();
    while (true)
    {
        // read packet
        // using ReadByte here would block if data is not available, which means I'm wasting a thread?
    }
}

Why is ReadByteAsync not there? Or am I missing something?

like image 722
wingerse Avatar asked Jun 14 '26 09:06

wingerse


1 Answers

Just use the already existing method ReadAsync, bending it in your favor:

private static async Task<byte> ReadByteAsync(Stream s)
{
    byte[] buffer = new byte[1];

    await s.ReadAsync(buffer, 0, 1);

    return buffer[0];
}

Homework for ya: factor out the buffer into a class-level field so it doesn't get created each method call.

like image 160
AgentFire Avatar answered Jun 15 '26 23:06

AgentFire