Как установить тайм-аут Socket.ConnectAsync?

Я читал о том, как проверить все прослушивающие серверы на определенном порту в локальной сети, и, наконец, я написал код, который работает так, как я хочу.
Я использую System.Threading.Tasks.Parallel для подключения на все 254 IP-адреса как можно быстрее
пример: 192.168.1. 1 - 192.168.1. 254

Что мне нужно, так это установить тайм-аут для этих попыток подключения, потому что для вывода сообщения «Connection Failed» при сбое требуется около 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] Sockets TCP
Извините за плохой английский и заранее благодарим ..


person Murhaf Sousli    schedule 16.03.2012    source источник
comment
15-20 секунд кажутся разумными для одной попытки подключения и очень хорошими для 254 попыток. Мой браузер дольше работает в режиме «вращающейся стрелки», если сервер не работает.   -  person Martin James    schedule 16.03.2012
comment
На самом деле, 20 секунд - это слишком мало, если у канала есть модем удаленного доступа. К счастью, такие ужасы почти все вымерли.   -  person Martin James    schedule 16.03.2012
comment
@MartinJames, как я уже упоминал, это локальная сеть ... большинство игр и приложений, которые показывают доступные хосты ... дают результат менее чем за 10 секунд. например [компьютер в любом месте, netsupport, half-life ... и т. д.] Я знаю, что они используют лучший алгоритм и способы получить это ... но мне это нужно в ближайшее время   -  person Murhaf Sousli    schedule 16.03.2012
comment
Я не вижу ничего плохого в твоем английском :)   -  person Mukus    schedule 18.11.2012


Ответы (2)


Я нашел решение.
сначала добавьте все созданные сокеты в список типа SocketAsyncEventArgs или типа Socket или
, а затем используйте System.Timers. Таймер, чтобы закрыть все ожидающие соединения и подключенное после того, как таймер сработает, то есть через 5 секунд. (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.
        }
    }

введите описание изображения здесь

person Murhaf Sousli    schedule 16.03.2012

Я не нашел встроенного механизма тайм-аута. Вы должны установить таймер и прервать соединение при его срабатывании. Что-то похожее на это: Как настроить таймаут подключения к сокету

person zmbq    schedule 16.03.2012
comment
Я не уверен насчет этого ... Создание внешнего таймера, например создание нового потока ... не кажется хорошим создавать 254 таймера - person Murhaf Sousli; 16.03.2012
comment
может быть, я бы установил один таймер для всех ... но я все же предпочитаю лучшую идею - person Murhaf Sousli; 16.03.2012
comment
Вам нужен только один таймер, потому что это одинаковый тайм-аут для всех подключений. - person zmbq; 16.03.2012
comment
@MurhafSousli Timers не работают в собственных потоках. См. Ответ на вопрос, который я задал некоторое время назад: stackoverflow.com/a/31833/3279 - person Ben Collins; 11.08.2015
comment
@ ZX9 - в этом вопросе они есть. Если у вас есть другой вопрос, вы должны опубликовать его как вопрос. - person zmbq; 20.10.2016