2011-08-01 33 views
3

私は非同期CTPフレームワークで練習をしています。練習として、(任意のプロトコルを使用して)サーバーにクエリを実行できるTCPクライアントを作成します。とにかく、私は接続の問題のために非常に初期の段階で立ち往生しています。私はまだいくつかの基本的な点を理解していないか、または奇妙な何かがあります。非同期TCPクライアント接続でハングアップ

だから、ここ非同期コネクタは次のとおりです。

public class TaskClient 
{ 
    public static Task<TcpClient> Connect(IPEndPoint endPoint) 
    { 
     //create a tcp client 
     var client = new TcpClient(AddressFamily.InterNetwork); 

     //define a function to return the client 
     Func<IAsyncResult, TcpClient> em = iar => 
     { 
      var c = (TcpClient)iar.AsyncState; 
      c.EndConnect(iar); 
      return c; 
     }; 

     //create a task to connect the end-point async 
     var t = Task<TcpClient>.Factory.FromAsync(
      client.BeginConnect, 
      em, 
      endPoint.Address.ToString(), 
      endPoint.Port, 
      client); 

     return t; 
    } 
} 

私は、任意の後続のクエリ(コードここでは図示せず)に使用するTcpClientインスタンスをバック持つ、一度だけ、この関数を呼び出すことを意味します。次のように

はどこか私の形で、私は上記の関数を呼び出す:

//this method runs on the UI thread, so can't block 
    private void TryConnect() 
    { 
     //create the end-point 
     var ep = new IPEndPoint(
      IPAddress.Parse("192.168.14.112"), //this is not reachable: correct! 
      1601); 

     var t = TaskClient 
      .Connect(ep) 
      .ContinueWith<TcpClient>(_ => 
      { 
       //tell me what's up 
       if (_.IsFaulted) 
        Console.WriteLine(_.Exception); 
       else 
        Console.WriteLine(_.Result.Connected); 

       return _.Result; 
      }) 
      .ContinueWith(_ => _.Result.Close()); 

     Console.WriteLine("connection in progress..."); 

     //wait for 2" then abort the connection 
     //Thread.Sleep(2000); 
     //t.Result.Client.Close(); 
    } 

テストは、リモートサーバーに接続しようとすることですが、それは到達不能である必要があります(上のPCが、サービスが停止しました)。リモートエンドポイントがオフになっているので、私はTryConnect機能を実行すると

、それは「進行中の接続...」を正しく返すとすぐに、例外が表示されます。優れた!

問題は、それが例外を返すために数秒を必要としていることであり、私は進行中の操作をキャンセルするために、ユーザーにチャンスを与えたいと思います。 BeginConnectメソッドに関するMSDNの仕様によれば、非同期操作を中止する場合は、作業ソケット上でCloseを呼び出すだけです。

だから、私は2秒後にユーザーがキャンセルをシミュレートするために、(上記のようにコメントアウト)最後に数行を追加しようとしました。結果はアプリ(砂時計)のハングアップとして見えます。 IDEを一時停止すると、最後の行であるt.Result.Client.Close()で停止します。しかし、IDEを停止することによって、例外なくすべて正常に終了します。

私はクライアントを直接t.Result.Close()として閉じようとしましたが、まったく同じです。

それは私ですか、接続プロセスに何か問題がありますか?

ありがとうございます。

答えて

1

オブジェクトにDispose()を呼び出してみてください。Close()よりも少し攻撃的です。 TcpClientクラスのさまざまなタイムアウトメンバーを見て、より適切な値に設定することができます(たとえば、LAN環境では1秒で十分でしょう)。また、.Net 4.0のCancellationTokenSource機能を見ることもできます。これにより、Taskに中止を希望する信号を送ることができます。articleが見つかりました。

また、実際に(プライマリスレッドだけでストールしている別のスレッドを待っているかもしれない)、例えば失速しているスレッドを知る必要があります.ContinueWith(_ => _.Result.Close())が問題になる可能性があります(ソケットを2回閉じるときの動作を確認する必要があります)。デバッグ中は、[スレッド]ウィンドウ([デバッグ] - > [Windows] - > [スレッド])を開き、各スレッドを確認します。

2

t.Result.Close()tタスクの完了を待ちます。 t.ContinueWith()もタスクの完了を待ちます。

キャンセルするには、tcpとタイマーの2つのタスクを待つ必要があります。
async tcp構文の使用:

await Task.WhenAny(t,Task.Delay(QueryTimeout)); 
if (!t.IsCompleted) 
    tcpClient.Close(); //Cancel task 
関連する問題