我已经设置了SmtpClient类的Timeout属性,但它似乎不起作用,当我给它一个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上实现,它也不起作用。
有人遇到过同样的问题吗?
答案 0 :(得分:16)
你问过是否有人遇到过同样的问题 - 我刚试过你的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
当我将时间输出更改为15000
时,我迟迟没有得到超时错误。
如果没有任何东西在端口25上侦听,或者主机无法访问,则在system.net.tcpclient
层超时后至少20秒才会发生超时。这低于system.net.mail
图层。来自excellent article describing the problem and solution:
您会注意到,System.Net.Sockets.TcpClient和System.Net.Sockets.Socket这两个类都没有连接套接字的超时。我的意思是你可以设置超时。在建立同步/异步套接字连接时调用Connect / BeginConnect方法时, .NET套接字不提供连接超时。相反,如果它尝试连接的服务器没有监听或者有任何网络错误,则在抛出异常之前,连接会被迫等待很长时间。 默认超时为20 - 30秒。
无法从邮件更改超时(这是有道理的,邮件服务器通常都已启动),实际上无法更改system.net.socket
的连接,这实在令人惊讶。但是你可以进行异步连接,然后可以判断你的主机是否启动并且端口是否打开。从this MSDN thread开始,特别是this post,此代码有效:
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.");
}
答案 1 :(得分:0)
添加到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
}
}
这个解决方案伴随着你在任务中没有得到异常细节的权衡。等等,但也许值得吗?