Тайм-аут SmtpClient не работает

Я установил свойство Timeout класса SmtpClient, но он, похоже, не работает, когда я даю ему значение 1 миллисекунды, тайм-аут на самом деле составляет 15 секунд при выполнении кода. Код, который я взял из в MSDN.

string to = "jane@contoso.com";
string from = "ben@contoso.com";
string subject = "Using the new SMTP client.";
string body = @"Using this new feature, you can send an e-mail message from an application very easily.";
MailMessage message = new MailMessage(from, to, subject, body);
SmtpClient client = new SmtpClient("1.2.3.4");
Console.WriteLine("Changing time out from {0} to 100.", client.Timeout);
client.Timeout = 1;
// Credentials are necessary if the server requires the client 
// to authenticate before it will send e-mail on the client's behalf.
client.Credentials = CredentialCache.DefaultNetworkCredentials;
client.Send(message);

Я пробовал реализацию на mono, она также не работает.

кто-нибудь сталкивался с той же проблемой?

2 ответов


воспроизведение вашего теста-это работает для меня

вы спросили, не сталкивался ли кто - нибудь с той же проблемой - я просто попробовал ваш код на Windows 7, VS 2008 с .NET 2.0-он работал просто отлично. С таймаутом, установленным в 1, как у вас есть, я получаю эту ошибку почти сразу:

Unhandled Exception: System.Net.Mail.SmtpException: The operation has timed out
   at System.Net.Mail.SmtpClient.Send(MailMessage message)
   at mailtimeout.Program.Main(String[] args) in c:\test\mailtimeout\Program.cs:line 29

Я думаю, что проблема может быть в том, что вы ожидаете чего-то другого от тайм-аута. Тайм-аут означает, что соединение было выполнено успешно, но ответ не вернулся от сервера. Это означает, что у вас должен быть сервер, прослушивающий порт 25 в пункте назначения, но он не отвечает. Для этого теста я использую на TCL чтобы создать сокет на 25, который ничего не сделал:

c:\> tclsh
% socket -server foo 25

когда я изменил timout на 15000, Я не получил ошибку тайм-аута unti l5s позже.

Почему Smtp.Тайм-аут не имеет никакого эффекта, если соединение не может быть сделано

если ничего не слушает на порте 25, или хозяин не достижим, то тайм-аут не произойдет, по крайней мере, до 20s, когда system.net.tcpclient время ожидания слоя. Это ниже system.net.mail слой. С отличная статья, описывающая проблему и решение:

вы заметите, что ни один из двух классов, система.Сеть.Розетки.TcpClient ни системы.Сеть.Розетки.Сокет имеет тайм-аут для подключения сокета. Я имею в виду тайм-аут, который вы можете установить. .NET сокеты не обеспечивают тайм-аут подключения при вызове Метод Connect/BeginConnect при установке синхронного / асинхронного сокета. Вместо этого connect вынужден ждать очень долго, прежде чем исключение будет вызвано, если сервер, к которому он пытался подключиться, не слушает или если есть какая-либо сетевая ошибка. время ожидания по умолчанию составляет 20 - 30 секунд.

нет возможности изменить этот тайм-аут от Почты (что имеет смысл, почтовые серверы обычно не работают), и на самом деле нет возможности изменить подключение от system.net.socket, что действительно удивительно. Но вы можете выполнить асинхронное подключение, а затем определить, открыт ли ваш хост и открыт ли порт. От этот поток MSDN и в частности этот пост этот код работает:

Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IAsyncResult result = socket.BeginConnect("192.168.1.180", 25, null, null);
// Two second timeout
bool success = result.AsyncWaitHandle.WaitOne(2000, true);
if (!success) {
    socket.Close();
    throw new ApplicationException("Failed to connect server.");
}

добавив к ответу ckhan, я хотел бы поделиться с вами предложением реализовать более короткий тайм-аут:

var task = Task.Factory.StartNew(() => SendEmail(email));

if (!task.Wait(6000))
   // error handling for timeout on TCP layer (but you don't get the exception object)

затем в SendEmail ():

using (var client = new SmtpClient(_serverCfg.Host, _serverCfg.Port)) 
{        
    try
    {
        client.Timeout = 5000;   // shorter timeout than the task.Wait()
        // ...
        client.Send(msg);
    }
    catch (Exception ex)
    {
        // exception handling
    }
}

это решение приходит с компромиссом, что вы не получаете детали исключения в задаче.Подожди, кейс, может, это того стоит?