David Diaz
David Diaz

Reputation: 148

NetworkStream Equivelant

I have been trying to create a metro application but there is a problem: StreamSocket doesn't really do what I want to do (I think)

Here is an excerpt my code from .Net that works:

        try
        {
            TCP = new TcpClient(server, port);
            Stream = TCP.GetStream();
            Read = new StreamReader(Stream);
            Write = new StreamWriter(Stream);
        }
        catch (Exception e)
        {
            Console.WriteLine("Error connecting to " + server + ": " + e);
            return;
        }

        // Identify
        Write.WriteLine("LOGIN " + Username);
        Write.Flush();

        while (Connected)
        {
            try
            {
                if ((line = Read.ReadLine()) != null && Connected)

I can't get StreamSocket to work... it requires you to know the length of the string that's coming in and I don't know what it will be - it varies. Is there any way to do this that will work?

This is what I have but it doesn't work:

        try
        {
            // Connect to the server (in our case the listener we created in previous step).
            await Socket.ConnectAsync(new HostName("example.com"), "1111");
        }
        catch (Exception exception)
        {
            // If this is an unknown status it means that the error is fatal and retry will likely fail.
            if (SocketError.GetStatus(exception.HResult) == SocketErrorStatus.Unknown)
            {
                throw;
            }
        }

        // Create a DataWriter if we did not create one yet. Otherwise use one that is already cached.
        Writer = new DataWriter(Socket.OutputStream);
        Listener = new DataReader(Socket.InputStream);

        Debug.WriteLine(Socket.Information.RemoteAddress.CanonicalName); //Check if IP is correct

        SendRaw("LOGIN " + Nickname);

        string line = "";
        Connected = true;
        while (Connected)
        {
            if (Listener.UnconsumedBufferLength != 0)
            {
                line = Listener.ReadString(Listener.UnconsumedBufferLength);
                Debug.WriteLine(line);
            }
        }
    }

    async public void SendRaw(string str)
    {
        Writer.WriteString(str);

        // Write the locally buffered data to the network.
        try
        {
            await Writer.StoreAsync();
        }
        catch (Exception exception)
        {
            // If this is an unknown status it means that the error if fatal and retry will likely fail.
            if (SocketError.GetStatus(exception.HResult) == SocketErrorStatus.Unknown)
            {
                throw;
            }
        }
    }

Any help would be appreciated!

Upvotes: 1

Views: 1518

Answers (1)

Stephen Cleary
Stephen Cleary

Reputation: 456332

First things first: your original code is a DOS attack waiting to happen. If possible, I would recommend changing the protocol to include a length prefix before every string so you can tell how big it will be before allocating memory for it.

Second things second: the DataReader class must read a number of bytes into its internal buffer before it can interpret them. You read into this buffer by calling LoadAsync.

However, if you want to read a string of arbitrary length, you'll have to read into a buffer and scan for your newline yourself, resizing the buffer (or adding new buffers) as necessary if the newline isn't found, up to some maximum size.

Update:

Set InputStreamOptions to Partial; the you can call LoadAsync with an arbitrary large buffer size (e.g. 1024). After getting data, call ReadString(UnconsumedBufferLength). Each time you do this, you may get part of a line, a line, or more than a line. So you'll have to build up a string and then Split by \n, keeping any partial line at the end for the next time through the loop.

Upvotes: 2

Related Questions