Search code examples
c#smtpbufferstreamreadertcplistener

Detect char in buffer before buffer is full


I'm writing a SMTP server as a exercise in learning TCP socketing.

I've hit a snag whereby I need to exit a ReadBlock by detecting the presence of a <CRLF>.<CRLF> in the buffer. The client connected to the SMTP server will end it's current sequence of data transmission with a <CRLF>.<CRLF>.

However, I don't know the best method of handling this.

I could write a timer which periodically reviews the current buffer for <CRLF>.<CRLF>, but this seems inefficient to me.

What is the best way of breaking out of the Read by detecting <CRLF>.<CRLF> ?

private static void Service()
        {
            while (true)
            {
                var theSocket = _listener.AcceptSocket();

                Console.WriteLine("Connected: {0}",theSocket.RemoteEndPoint);

                try
                {
                    Stream s = new NetworkStream(theSocket);

                    var socketReader = new StreamReader(s);     
                    var socketWriter = new StreamWriter(s) {AutoFlush = true};

                    socketWriter.WriteLine("Hello {0}",theSocket.RemoteEndPoint);

                    using (var fileWriter = new StreamWriter(@"E:\test\tmp.txt",true))
                    {                        
                        do
                        {
                            fileWriter.WriteLine(theSocket.RemoteEndPoint);

                            char[] buf = new char[40];
                            int read = socketReader.ReadBlock(buf, 0, 40);

                            while (read != 0)
                            {
                                fileWriter.Write(buf,0,read);
                                fileWriter.WriteLine();
                                read = socketReader.ReadBlock(buf, 0, 40);                             
                            }                            
                        } while (true);

                    }                    
                    s.Close();                  
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);                   
                }

                Console.WriteLine("Disconnected: " +  theSocket.RemoteEndPoint);

                theSocket.Close();

            }
        }

Solution

  • ReadBlock is not a blocking read. It will return immediately, with up to the maximum number of characters specified in the call (40 in your case).

    The method blocks until either count characters are read, or the end of the stream has been reached. This is a blocking version of Read.

    http://msdn.microsoft.com/en-us/library/system.io.streamreader.readblock(v=vs.110).aspx

    You can simply check your buffer for CRLF as needed as soon as the call returns.

    Alternatively as suggested in the comments, ReadLine() may be suitable for your needs.