Как я могу заставить TcpListener принимать несколько соединений и работать с каждым отдельно?
У меня есть SMTP-прослушиватель, который работает хорошо, но может принимать только одно соединение. Мой код С# ниже, и я запускаю его как службу. Моя цель - запустить его на сервере и развернуть несколько сообщений 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();
}
}
}
Ответы
Ответ 1
Вы можете разделить большую часть вашего кода на отдельный поток:
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
}
Ответ 2
Вы почти наверняка хотите соединить каждое соединение в другой поток. Таким образом, у вас есть вызов "accept" в цикле:
while (listening)
{
TcpClient client = listener.AcceptTcpClient();
// Start a thread to handle this client...
new Thread(() => HandleClient(client)).Start();
}
Очевидно, вы захотите настроить, как вы создаете потоки (возможно, используете пул потоков, возможно, TPL и т.д.) и как вы прекратите слушатель изящно.
Ответ 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