2011-03-17 19 views
11

मेरे पास एक एसएमटीपी श्रोता है जो अच्छी तरह से काम करता है लेकिन केवल एक कनेक्शन प्राप्त करने में सक्षम है। मेरा सी # कोड नीचे है और मैं इसे एक सेवा के रूप में चला रहा हूं। मेरा लक्ष्य यह है कि इसे सर्वर पर रनइन करें और इसे भेजे गए कई SMTP संदेशों को पार्स करें।मैं टीसीपी लिस्टनर को एकाधिक कनेक्शन स्वीकार करने और व्यक्तिगत रूप से प्रत्येक के साथ काम करने के लिए कैसे प्राप्त करूं?

वर्तमान में यह पहला संदेश पार्स करता है और काम करना बंद कर देता है। मैं इसे दूसरे, तीसरे, चौथे को स्वीकार करने के लिए कैसे प्राप्त कर सकता हूं ... एसएमटीपी संदेश और इसे संसाधित करता है जैसे यह पहला होता है?

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Net.Sockets; 
using System.Net; 
using System.IO; 

namespace SMTP_Listener 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 


      TcpListener listener = new TcpListener(IPAddress.Any , 8000); 
      TcpClient client; 
      NetworkStream ns; 

      listener.Start(); 

      Console.WriteLine("Awaiting connection..."); 
      client = listener.AcceptTcpClient(); 
      Console.WriteLine("Connection accepted!"); 

      ns = client.GetStream(); 

      using (StreamWriter writer = new StreamWriter(ns)) 
      { 
       writer.WriteLine("220 localhost SMTP server ready."); 
       writer.Flush(); 

       using (StreamReader reader = new StreamReader(ns)) 
       { 
        string response = reader.ReadLine(); 

        if (!response.StartsWith("HELO") && !response.StartsWith("EHLO")) 
        { 
         writer.WriteLine("500 UNKNOWN COMMAND"); 
         writer.Flush(); 
         ns.Close(); 
         return; 
        } 

        string remote = response.Replace("HELO", string.Empty).Replace("EHLO", string.Empty).Trim(); 

        writer.WriteLine("250 localhost Hello " + remote); 
        writer.Flush(); 

        response = reader.ReadLine(); 

        if (!response.StartsWith("MAIL FROM:")) 
        { 
         writer.WriteLine("500 UNKNOWN COMMAND"); 
         writer.Flush(); 
         ns.Close(); 
         return; 
        } 

        remote = response.Replace("RCPT TO:", string.Empty).Trim(); 
        writer.WriteLine("250 " + remote + " I like that guy too!"); 
        writer.Flush(); 

        response = reader.ReadLine(); 

        if (!response.StartsWith("RCPT TO:")) 
        { 
         writer.WriteLine("500 UNKNOWN COMMAND"); 
         writer.Flush(); 
         ns.Close(); 
         return; 
        } 

        remote = response.Replace("MAIL FROM:", string.Empty).Trim(); 
        writer.WriteLine("250 " + remote + " I like that guy!"); 
        writer.Flush(); 

        response = reader.ReadLine(); 

        if (response.Trim() != "DATA") 
        { 
         writer.WriteLine("500 UNKNOWN COMMAND"); 
         writer.Flush(); 
         ns.Close(); 
         return; 
        } 

        writer.WriteLine("354 Enter message. When finished, enter \".\" on a line by itself"); 
        writer.Flush(); 

        int counter = 0; 
        StringBuilder message = new StringBuilder(); 

        while ((response = reader.ReadLine().Trim()) != ".") 
        { 
         message.AppendLine(response); 
         counter++; 

         if (counter == 1000000) 
         { 
          ns.Close(); 
          return; // Seriously? 1 million lines in a message? 
         } 
        } 

        writer.WriteLine("250 OK"); 
        writer.Flush(); 
        ns.Close(); 
        // Insert "message" into DB 
        Console.WriteLine("Received message:"); 
        Console.WriteLine(message.ToString()); 
       } 
      } 

      Console.ReadKey(); 
     } 
    } 
} 

उत्तर

25

आप एक अलग थ्रेड में अपने कोड के सबसे को अलग कर सकते हैं:

static void Main(string[] args) 
{ 
    TcpListener listener = new TcpListener(IPAddress.Any , 8000); 
    TcpClient client; 
    listener.Start(); 

    while (true) // Add your exit flag here 
    { 
     client = listener.AcceptTcpClient(); 
     ThreadPool.QueueUserWorkItem(ThreadProc, client); 
    } 
} 
private static void ThreadProc(object obj) 
{ 
    var client = (TcpClient)obj; 
    // Do your work here 
} 
+0

क्यों 'BeginAcceptTcpClient' के साथ नहीं? इस तरह के एक बहुत ही सरल उदाहरण में यह जरूरी नहीं है, लेकिन यदि कोई जीयूआई है, तो async 'BeginAcceptTcpClient' ठंड से बच जाएगा। – i486

18

आप लगभग निश्चित रूप से एक और धागा में प्रत्येक कनेक्शन स्पिन करना चाहते हैं:

यहाँ मेरी कोड है। तो तुम एक पाश में "स्वीकार" फोन है:

while (listening) 
{ 
    TcpClient client = listener.AcceptTcpClient(); 
    // Start a thread to handle this client... 
    new Thread(() => HandleClient(client)).Start(); 
} 

जाहिर है आप को समायोजित करने के लिए कैसे आप धागे अंडे चाहता हूँ और कैसे आप श्रोता शान से रोक (शायद थ्रेड पूल, हो सकता है TPL आदि का उपयोग करें)।

+0

यह समाधान कैसे स्केल करेगा? क्या यह दो धागे होने के लिए समझदार होगा - आने वाले अनुरोधों को स्पूल करने के लिए एक धागा और दूसरा हेम के माध्यम से पुन: प्रयास करने और उन्हें संसाधित करने के लिए? – kacalapy

+1

@kacalapy: यह ज्यादातर स्थितियों के लिए ठीक पैमाने पर स्केल करेगा, हालांकि आप शायद थ्रेड पूल का उपयोग करना चाहते हैं। आप नहीं चाहते हैं कि एक कनेक्शन को मोड़ने से पहले पूरी तरह संसाधित होने के लिए किसी अन्य के लिए इंतजार करना पड़े। –

+0

@ जोन्ससेट आप सर्वोत्तम परिणाम के लिए क्या सिफारिश करेंगे? ThePretender उत्तर की तरह थ्रेडपूल का उपयोग करना? –

3

मैं जानता हूँ कि इस पुराने सवाल है, लेकिन मुझे यकीन है कि कई इस जवाब की तरह होगा।

// 1 
while (listening) 
{ 
    TcpClient client = listener.AcceptTcpClient(); 
    // Start a thread to handle this client... 
    new Thread(() => HandleClient(client)).Start(); 
} 

// 2 
while (listening) 
{ 
    TcpClient client = listener.AcceptTcpClient(); 
    // Start a task to handle this client... 
    Task.Run(() => HandleClient(client)); 
} 

// 3 
public async void StartListener() //non blocking listener 
{ 
    listener = new TcpListener(ipAddress, port); 
    listener.Start(); 
    while (listening) 
    { 
     TcpClient client = await listener.AcceptTcpClientAsync().ConfigureAwait(false);//non blocking waiting      
     // We are already in the new task to handle this client... 
     HandleClient(client); 
    } 
} 
//... in your code 
StartListener(); 
//... 
//use Thread.CurrentThread.ManagedThreadId to check task/thread id to make yourself sure 
+1

क्या होगा यदि हैंडल क्लाइंट() 'async है क्योंकि उस फ़ंक्शन में हम स्ट्रीमर से 'ReadLineAsync()' का इंतजार कर रहे हैं? –