我如何让TcpListener接受多个连接并单独使用每个连接?

时间:2011-03-17 13:38:44

标签: c# .net smtp tcplistener

我有一个运行良好的SMTP侦听器,但只能接收一个连接。我的C#代码如下,我将其作为服务运行。我的目标是让它在服务器上运行并解析发送给它的多个smtp消息。

目前它会解析第一条消息并停止工作。我怎样才能让它接受第2,第3,第4 ...... SMTP消息并像第一个那样处理它?<​​/ p>

这是我的代码:

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

4 个答案:

答案 0 :(得分:29)

您可以将大部分代码分解为单独的线程:

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
}

答案 1 :(得分:23)

您几乎肯定希望将每个连接转换为另一个线程。所以你在循环中有“接受”调用:

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

显然你会想要调整你如何产生线程(可能使用线程池,也许是TPL等)以及如何优雅地停止监听器。

答案 2 :(得分:6)

我知道这是一个老问题,但我相信很多人会喜欢这个答案。

undefined method `banks' for nil:NilClass

Extracted source (around line #10):

    def show
        @pools = @deal.pools
10      @banks = @pool.banks
    end

    def new

答案 3 :(得分:1)

根据您的代码,您正在启动一个侦听器,并接收和处理消息并关闭程序。

您需要维护一个侦听器,并且TcpClient对象可以传递给另一个函数来处理收到的消息。 listener.Start();

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