web-dev-qa-db-fra.com

Comment puis-je obtenir TCplistener pour accepter plusieurs connexions et travailler avec chacun individuellement?

J'ai un auditeur SMTP qui fonctionne bien mais ne peut recevoir que pour recevoir une connexion. Mon code C # est ci-dessous et je l'utilise comme service. Mon objectif est de le faire punir sur un serveur et d'analyser plusieurs messages SMTP qui lui sont envoyés.

actuellement, il analyse le premier message et cesse de fonctionner. Comment puis-je l'accepter d'accepter le message 2ème, 3ème, 4ème ... SMTP et le processus comme ça fait le premier?

voici mon code:

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();
        }
    }
}
18
kacalapy

Vous pouvez prendre la majeure partie de votre code dans un fil séparé:

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
}
30
Oleg Tarasov

Vous voulez presque certainement tourner chaque connexion dans un autre fil. Donc, vous avez l'appel "Accepter" dans une boucle:

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

De toute évidence, vous voudrez ajuster la manière dont vous entretenez des threads (peut-être utiliser la piscine de thread, peut-être TPL, etc.) et la façon dont vous arrêtez l'auditeur gracieusement.

24
Jon Skeet

Je sais que c'est une mauvaise question mais je suis sûr que beaucoup aimeront cette réponse.

// 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
6
MrHIDEn