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

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

目前它解析第一条消息并停止工作。 我怎样才能让它接受第2,第3,第4 …… 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(); } } } 

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

 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 } 

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

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

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

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

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