Страницы

Поиск по вопросам

пятница, 13 марта 2020 г.

Многопоточное подключение к SSH

#c_sharp #многопоточность #ssh


Наставьте на путь истинный, подскажите, что можно сделать/почитать по этому поводу?

Есть список объектов типа IP.

class IP
{
    public string host;
    public string login;
    public string password;
}


И метод, который перебирает этот список в параллельном цикле, в котором происходит
подключение к SSH. 

public void Cycle()
{
  int port = 22;

  Parallel.ForEach(ipList, ipObject =>
  {
       string ip = ipObject.host;
       string login = ipObject.login;
       string password = ipObject.password;

       SshConnect(ip, port, login, password);
  });
}


Метод SSHConnect реализован с помощью библиотеки Renci.SSHNet. Выглядит следующим
образом:

private bool SshConnect(string host, int port, string login, string password)
 {
     bool flag = true;
     try
     {
          var client = new SshClient(host, port, login, password);
          client.Connect();
          client.Disconnect();
     }
     catch
     {
          flag = false;
     }
     return flag;
 }


Все бы ничего, но скорость перебора и подключения к SSH ужасно медленная. Что можно
сделать, чтобы увеличить скорость?

P.S. Раньше у меня был алгоритм, который работал, как минимум, в 2 раза быстрее этого.

В нем я использовал один поток, в котором находился цикл, перебирающий список и в
этом же потоке создавалось определенное количество других потоков, которые в свою очередь
обрабатывали эти элемента списка.

На другом форуме сказали, что так делать нежелательно и немного почитав, я решил
попробовать Paralel.ForEach, но результат не оправдал ожиданий.
    


Ответы

Ответ 1



Основное время при подключении по ssh тратит не процессор, а сеть - пакет TCP SYN слишком долго идет до сервера и обратно. В таких условиях надо и правда создавать как можно больше потоков, Paralel.ForEach же ограничивает их число. У вас есть список ssh-серверов, с которыми надо что-то сделать - или вы сканируете сеть? Во втором случае можно сделать оптимизацию. Сначала можно проверить, открыт ли порт 22 - а уже потом подключаться по ssh там, где он открыт. Это можно сделать параллельно, но вовсе без потоков, при помощи асинхронного программирования: var taskList = ipList.Select(async ipObject => { try { using (var c = new TcpClient()) await c.ConnectAsync(ipObject.host, 22); retrun ipObject; } catch { return null; } }).ToArray(); Task.WaitAll(taskList); ipList = taskList.Select(task => task.Result).Where(ipObject => ipObject != null).ToList(); // Теперь в ipList остались только хосты, которые отвечают на порту 22

Комментариев нет:

Отправить комментарий