2014-10-27 3 views
1

Как вы можете видеть, я работаю на SMTP-сервере, написанном на C#. Я включил весь код (один класс не входит), но я надеюсь, что вы получите хороший обзор деталей. Я борюсь с сообщением DATA от клиента, проблема в моей точке зрения не работает «Auto Flush». Клиент отправляет на мой сервер «DATA», чтобы сообщить мне, чтобы я получил данные для моего письма. Мне нужно ответить «354 start mail input», что я и делаю, моя проблема: После отправки «354 start mail input» мне нужно получить сообщение от клиента в этом funtion.Автоматический поток потока tcp не работает

using System; 
using System.Text; 
using System.Net; 
using System.Net.Sockets; 
using System.Threading; 

namespace FakeSMTP 
{ 
public class SMTPServer //: IDisposable 
{ 
    TcpClient client; 
    NetworkStream stream; 
    System.IO.StreamReader reader; 
    System.IO.StreamWriter writer; 
    //public void Dispose() 
    //{ 
    // writer.Dispose(); 
    // reader.Dispose(); 
    // stream.Dispose(); 
    //} 


    public SMTPServer(TcpClient client) 
    { 
     this.client = client; 
     stream = client.GetStream(); 
     reader = new System.IO.StreamReader(stream); 
     writer = new System.IO.StreamWriter(stream); 
     writer.NewLine = "\r\n"; 
     writer.AutoFlush = true; 
    } 

    static void Main(string[] args) 
    { 
     TcpListener listener = new TcpListener(IPAddress.Loopback, 25); 
     listener.Start(); 
     //using (SMTPServer handler = new SMTPServer(listener.AcceptTcpClient())) 
     while (true) 
     { 
      SMTPServer handler = new SMTPServer(listener.AcceptTcpClient()); 
      Thread thread = new System.Threading.Thread(new ThreadStart(handler.Run)); 
      thread.Start(); 
     } 
    } 

    public void Run() 
    { 

     string sadress; 
     string radress; 
     string rserver; 
     bool auth = false; 
     writer.WriteLine("220 smtp.localsmtp.de ESMTP server ready"); 
     for (string line = reader.ReadLine(); line != null; line = reader.ReadLine()) 
     { 
      Console.Error.WriteLine("Read line {0}", line); 

      if (line.StartsWith("EHLO")) 
       { 
       writer.WriteLine("250-smtp.localsmtp.de"); 
       //Auth ankuendigen 
       writer.WriteLine("250 AUTH PLAIN"); 
       } 

      if (line.StartsWith("QUIT")) 
       { 
       writer.WriteLine("221 Bye Sweetie see ya"); 
       client.Close(); 
       } 

      #region auth 

      if (line.StartsWith("AUTH PLAIN")) 
      { 
       Console.WriteLine("client sendet Auth: " + line); 
       string [] pw = line.Split(new string[] { "PLAIN " }, StringSplitOptions.None); 
       byte[] bytes = Convert.FromBase64String(pw[1]); 
       string result = Encoding.BigEndianUnicode.GetString(bytes); 

       if (result == "12") 
        { 
         writer.WriteLine("235 2.7.0 Authentication successful"); 
         auth = true; 
        } 
       else 
        { 
         Console.WriteLine("Falsche AUTH Daten"); 
         writer.WriteLine("535 – Incorrect authentication data"); 

        } 
      } 
       #endregion 

      #region sender 
      if (line.StartsWith("MAIL FROM") && auth == true) 
       { 
       string[] sadressa = line.Split(new string[] { "FROM:" }, StringSplitOptions.None); 
       sadress = sadressa[1]; 
       //Absender 
       sadress = sadress.Replace("<","").Replace(">",""); 
       //Debug 
       Console.WriteLine("Absender: " + sadress); 
       writer.WriteLine("250 OK"); 
       } 

      #endregion 

      #region receiver 
      if (line.StartsWith("RCPT TO:") && auth == true) 
       { 
        string[] radressa = line.Split(new string[] { "RCPT TO:" }, StringSplitOptions.None); 
        radress = radressa[1]; 
        //Empfänger 
        radress = radress.Replace("<", "").Replace(">", ""); 
        if (samplesmtp.getMX.GetMXRecord(radress) != "invalid") 
        { 
         rserver = samplesmtp.getMX.GetMXRecord(radress); 
         Console.WriteLine("MX Record: " + rserver); 
        } 
        else 
         Console.WriteLine("ALARM"); 


        //Debug 
        Console.WriteLine("Empfänger: " + radress); 
        writer.WriteLine("250 OK"); 
       } 
      #endregion 

      #region data 

      if (line.StartsWith("DATA") && auth == true) 
      { 
       writer.WriteLine("354 start mail input"); 

       var emailLine = reader.ReadLine(); 
       while (!emailLine.Equals(".")) 
       { 
        // add emailLine to the email body 
        string[] emailbody = new string[] {emailLine}; 
        Console.WriteLine("Emailbody: " + emailbody[0]); 
       } 
       reader.Close(); 
       writer.Close(); 
       stream.Dispose(); 
       writer.WriteLine("250 OK"); 
      } 

      #endregion 

     } 
     } 
    } 
} 

Попытка вызова .Flush() вручную в коде не изменяет проблему вообще. Нет эффекта.

+0

Ваш класс должен реализовать 'IDisposable' как это имеет целый ряд объектов, которые реализуют' IDisposable', а также (т.е. все его члены). –

+0

Как использовать .Dispose Methode в моем контексте? – Pekinese

ответ

1

В ответ на ваш актуальный вопрос вы хотите, чтобы прочитать все строки, пока вы не получите. на трассе на своем собственном (см https://www.ietf.org/rfc/rfc2821.txt), что-то вроде этого: -

var emailLine = reader.ReadLine(); 
while (!emailLine.Equals(".")) 
{ 
    // add emailLine to the email body 
    emailLine = reader.readLine(); 
} 
writer.WriteLine("250 OK"); 
reader.Close(); 
writer.Close(); 
stream.Dispose(); 
+0

Нет, я не хочу редактировать весь свой код. Моя проблема: после того, как клиент сказал мне «DATA», я отвечаю на «354 start mail input». Теперь клиент отправил мне весь почтовый ящик, но это должно быть в выражении if выше (в строке 'if (line .StartsWith ("DATA") && auth == true) 'block. Как я сказал выше, значение' line' не изменяется в этом внутреннем if-блоке. Мне нужно, чтобы поток был очищен/удален между двумя if blocks. – Pekinese

+0

Я предлагал вам поместить этот код между двумя блоками if, извините, если это было неясно. В вашем примере кода фактически нет строк между двумя блоками if, поэтому это, вероятно, корень вашей проблемы. записывая ваше сообщение 354 и проверяя значение строки снова –

+0

Я отредактировал код выше, вы имеете в виду код, подобный этому, или мне нужно добавить еще один оператор if в цикл while? Код, кажется, бесконечный цикл на данный момент. – Pekinese

1

В ответ на ваш комментарий к моему:

public class SMTPServer : IDisposable 
{ 
    // all the other stuff 

    public void Dispose() 
    { 
     writer.Dispose(); 
     reader.Dispose(); 
     stream.Dispose(); 
    } 
} 

код вызова:

static void Main(string[] args) 
{ 
    TcpListener listener = new TcpListener(IPAddress.Loopback, 25); 
    listener.Start(); 
    using (SMTPServer handler = new SMTPServer(listener.AcceptTcpClient())) 
    { 
     while (true) 
     { 
      Thread thread = new System.Threading.Thread(new ThreadStart(handler.Run)); 
      thread.Start(); 
     } 
    } 
} 
+0

Прежде всего спасибо за ответ Джесси. Я редактировал код в первом сообщении. Использование вашего решения не работает мной. Компилятор рассказал мне через некоторое время, что он не может получить доступ к с кодом 'for (string line = reader.ReadLine(); line! = Null; line = reader.ReadLine())' из-за того, что он заблокирован IDisposable. Любая идея, где я делаю неправильно? – Pekinese

+0

Ум, что? Боюсь, я не понимаю. –

+0

Я опубликовал новый ответ в нижней части этой страницы. Мне нужно получить значение 'line', сброшенное между двумя внутренними блоками if (конец кода, я использовал комментарии, чтобы показать, что я хочу делать в коде). – Pekinese

Смежные вопросы