9

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

モノラルで実装してみましたが、動作しません。

誰かが同じ問題に遭遇しましたか?

4

2 に答える 2

16

あなたのテストを再現する-それは私のために働く

あなたは誰かが同じ問題に遭遇したかどうか尋ねました-私はちょうどあなたのコードをWindows7、VS2008で.NET2.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

タイミングをに変更したとき、150005秒後にタイムアウトエラーが発生しませんでした。

接続できない場合にSmtp.Timeoutが効果を発揮しない理由

system.net.tcpclientポート25で何もリッスンしていない場合、またはホストに到達できない場合、タイムアウトは、レイヤーがタイムアウトする少なくとも20秒まで発生しません。これはsystem.net.mailレイヤーの下にあります。問題と解決策を説明する優れた記事から:

System.Net.Sockets.TcpClientとSystem.Net.Sockets.Socketの2つのクラスのどちらにも、ソケットを接続するためのタイムアウトがないことに気付くでしょう。私はあなたが設定できるタイムアウトを意味します。.NETソケットは、同期/非同期ソケット接続の確立中にConnect / BeginConnectメソッドを呼び出すときに、接続タイムアウトを提供しません。代わりに、接続しようとしたサーバーがリッスンしていない場合、またはネットワークエラーが発生した場合、接続は非常に長い時間待機してから例外がスローされます。デフォルトのタイムアウトは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.");
}
于 2012-05-06T04:38:18.587 に答える
2

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

このソリューションには、タスクで例外の詳細を取得しないというトレードオフがあります。待機しますが、それだけの価値はありますか?

于 2015-04-08T16:20:41.107 に答える