2012-03-16 94 views
3

私は、LAN上の特定のポート上のすべてのリスニングサーバをチェックする方法について読んできました。最後に、私が望むように動作するコードを書きました。
私はSystem.Threading.Tasks.Parallelを使用して、すべての254個のIPアドレスにできるだけ早く接続します。
ex: 192.168.1。 - 192.168.1。私は必要なものSocket.ConnectAsyncのタイムアウトを設定するには?

それは印刷に約15〜20秒かかりますので、これらの接続試行のタイムアウトを設定することです。それが失敗したときに「接続に失敗しました」..ので、私はそれをどのように行うのですか?ここで

は、クライアントのコードです:

static void Main(string[] args) 
    { 
     Console.WriteLine("Connecting to IP addresses has started. \n"); 

     Parallel.For(1, 255, i => 
     { 
      Connect("192.168.1." + i); 
     }); 
     Console.ReadLine(); 
    } 

    private static void Connect(string ipAdd) 
    { 
     Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
     SocketAsyncEventArgs e = new SocketAsyncEventArgs(); 
     IPEndPoint ipEnd = new IPEndPoint(IPAddress.Parse(ipAdd), 9990); 
     e.RemoteEndPoint = ipEnd; 
     e.UserToken = s; 
     e.Completed += new EventHandler<SocketAsyncEventArgs>(e_Completed); 
     Console.WriteLine("Trying to connect to : " + ipEnd); 
     s.ConnectAsync(e); 
    } 
    private static void e_Completed(object sender, SocketAsyncEventArgs e) 
    { 
     if (e.ConnectSocket != null) 
     { 
      StreamReader sr = new StreamReader(new NetworkStream(e.ConnectSocket)); 
      Console.WriteLine("Connection Established : " + e.RemoteEndPoint + " PC NAME : " + sr.ReadLine()); 
     } 
     else 
     { 
      Console.WriteLine("Connection Failed : " + e.RemoteEndPoint); 
     } 
    } 

サーバコード:

static void Main(string[] args) 
    { 
     Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
     IPEndPoint ep = new IPEndPoint(IPAddress.Any,9990); 
     server.Bind(ep); 
     server.Listen(100); 
     Socket client = server.Accept(); 
     NetworkStream stream = new NetworkStream(client); 
     StreamWriter sw = new StreamWriter(stream) 
     sw.WriteLine(System.Environment.MachineName); 
     sw.Flush(); 
     sw.Dispose(); 
     stream.Dispose(); 
     client.Dispose(); 
     server.Dispose(); 
    } 

それはより良い私に教えてくださいする任意のヒントや注意事項がある場合。私は[.Net 4.0]ソケットTCPを使用しています
私の悪い英語とおかげで申し訳ありません前もって。

+1

15〜20秒は1回の接続試行のための合理的と254回の試みのために非常に良いようです。サーバーがダウンしている場合、私のブラウザーは '回転矢印'モードのブラウザーよりも長い時間を費やしています。 –

+0

実際には、リンクにダイヤルアップモデムがある場合、20秒が短すぎます。幸いにも、そのような恐怖はほとんどすべてが死亡した。 –

+1

@MartinJamesこれは私が言及したようにローカルエリアネットワークです。利用可能なホストを示すほとんどのゲームとアプリケーション.. 10秒以内に結果を出してください。私は彼らがより良いアルゴリズムとそれを得る方法を使用していることを知っている..しかし、私は短時間でそれを必要とする –

答えて

3

解決策を見つけました。
は、第1のタイプのリストに作成されたすべてのソケットを追加SocketAsyncEventArgsまたはソケットまたは
の種類 、すべての保留中の接続と5秒後にあるタイマー刻みとき後に接続された一方を閉じることでSystem.Timers.Timerを使用。 (timer.Interval = 5000)。

クライアントコード:

//I've changed my console application to Winform 
    public ServerDiscovery() 
    { 
     InitializeComponent(); 
     timer.Elapsed += timer_tick; 
    } 

    System.Timers.Timer timer = new System.Timers.Timer(5000); 
    List<SocketAsyncEventArgs> list = new List<SocketAsyncEventArgs>(); 

    private void btnRefresh_Click(object sender, EventArgs e) 
    { 
     timer.Start(); 
     Parallel.For(1, 255, (i, loopState) => 
     { 
      ConnectTo("192.168.1." + i); 
     }); 
    } 

    private void ConnectTo(string ipAdd) 
    { 
     Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
     SocketAsyncEventArgs e = new SocketAsyncEventArgs(); 
     e.RemoteEndPoint = new IPEndPoint(IPAddress.Parse(ipAdd), 9990); 
     e.UserToken = s; 
     e.Completed += new EventHandler<SocketAsyncEventArgs>(e_Completed); 
     list.Add(e);  // Add to a list so we dispose all the sockets when the timer ticks. 
     s.ConnectAsync(e); 
    } 

    private void e_Completed(object sender, SocketAsyncEventArgs e) 
    { 
     if (e.ConnectSocket != null)  //if there's a connection Add its info to a listview 
     { 
      StreamReader sr = new StreamReader(new NetworkStream(e.ConnectSocket)); 
      ListViewItem item = new ListViewItem(); 
      item.Text = sr.ReadLine(); 
      item.SubItems.Add(((IPEndPoint)e.RemoteEndPoint).Address.ToString()); 
      item.SubItems.Add("Online"); 
      AddServer(item); 
     } 
    } 

    delegate void AddItem(ListViewItem item); 
    private void AddServer(ListViewItem item) 
    { 
     if (InvokeRequired) 
     { 
      Invoke(new AddItem(AddServer), item); 
      return; 
     } 
     listServer.Items.Add(item); 
    } 

    private void timer_tick(object sender, EventArgs e) 
    { 
     timer.Stop(); 
     foreach (var s in list) 
     { 
      ((Socket)s.UserToken).Dispose();  //disposing all sockets that's pending or connected. 
     } 
    } 

enter image description here

1

私は組み込みのタイムアウトメカニズムを見つけることができませんでした。タイマーを設定し、トリガするときに接続を中止する必要があります。これと似たようなもの:How to configure socket connect timeout

+1

私はそれについてはわかりません..新しいスレッドを作成するような外部タイマーを作成..それは254タイマーを作成するために良いとは思わない –

+1

多分私はすべてのそれらのための1つのタイマーを設定するだろう..しかし、私はまだ良いアイデアを好む –

+2

すべての接続に同じタイムアウトがあるため、1つのタイマーだけが必要です。 – zmbq

関連する問題