Вопрос по С#: Как отсоединится от SSH, что работает в потоке
Цитата: Alex от 28.11.2022, 14:39Всем здравствуйте. Прошу помощи для выхода из тупика. Суть его вот в чем. Я пишу VNC-клиен, однако топология сети такая, что приходится сначала пробрасывать порт через SSH, а уже потом подсоединяться к локалхосту. Для VNC я использую библиотеку vncsharp, а для SSH - Renci.sshnet. В потоке я запускаю метот, который одновременно рисует контролы, создает соединение SSH и VNC. Как теперь залезть в этот поток(или грохнуть его вовсе), чтоб отсоединиться от SSH и освободить порт. От VNC я освобождаюсь перебирая контролы в панеле на форме и сравниваю их тэги, но у ssh нет контрола, по этому такой вопрос. Может я туплю и подход неверный?
[spoiler title="Ниже код метода который пробрасывает порт и подключается к VNC"]private void VNCConnect(string shop, string pc) { VncSharp.RemoteDesktop remoteDesktop = new VncSharp.RemoteDesktop(); Parallel.Invoke( ()=> { BeginInvoke((MethodInvoker)( () => { GetShopSettings(shop, pc, out string IPSSH, out string IPConnect, out string SSHLogin, out string SSHPass, out string VNCPass);//Тут я выполняю SQL процедурку и получаю настройки ПК к которому буду подключаться if (IPSSH != "" && IPConnect != "") { AuthenticationMethod auth = new PasswordAuthenticationMethod(SSHLogin, SSHPass); ConnectionInfo coninfo = new ConnectionInfo(IPSSH, 22, SSHLogin, sysips.Contains(IPConnect.Substring(0, IPConnect.LastIndexOf("."))) ? ProxyTypes.None : ProxyTypes.Http, "IP-proxy", 3128, "login", "pass", auth);//Если я нахожусь в одной подсети с хостом, к которому подключаюсь, но не использовать прокси, иначе использовать SshClient sshclient = PingHost(IPSSH) ? new SshClient(IPSSH, 22, SSHLogin, SSHPass) : new SshClient(coninfo); // Если конечный хост пингуется, то подключиться без прокси, иначе через предыдущий метод(Сильно замудрено, в дальнейшем упростить) try { sshclient.Connect(); } catch (Exception ex) { if (sysips.Contains("10.21.")) { if (PingHost("10.21.200.52"))//Если я в одной подсети с прокси-сервером и он пингуется, то хост недоступен frmMessageBox.Show("Не могу подключиться к хосту", "Хост недоступен \n" + ex.Message, "important"); //Создал кастомную форму с классом Show else frmMessageBox.Show("Не могу подключиться к прокси", "Прокси-сервер недоступен \n" + ex.Message, "important"); } frmMessageBox.Show("Не могу подключиться к хосту", "Хост недоступен \n" + ex.Message, "important"); return; } int tunelport = 5900; while (tunelport < 5950)//Пробую пробросить порт VNC, если не получается - инкрементирую порт на 1 и пробую повторно { var portvnc = new ForwardedPortLocal("127.0.0.1", (uint)tunelport, "127.0.0.1", 5900); sshclient.AddForwardedPort(portvnc); try { portvnc.Start(); break; } catch (Exception) { sshclient.RemoveForwardedPort(portvnc); portvnc.Dispose(); tunelport++; } if (tunelport == 5950) { frmMessageBox.Show("Не могу подключиться", "К сожалению все порты заняты.\n" + "Попробуйте закрыть одно из соединений к этому магазину", "info"); return; } } remoteDesktop.GetPassword = new VncSharp.AuthenticateDelegate(() => VNCPass); remoteDesktop.VncPort = tunelport; remoteDesktop.Connect("127.0.0.1", false, true);//Порт проброшен - подключаемся к себе через проброшеный порт } })); }, ()=> {//Рисую VNC клиент BeginInvoke((MethodInvoker)( () => { remoteDesktop.Dock = DockStyle.Fill; remoteDesktop.Tag = $"{shop},{pc}"; pnlMain.Controls.Add(remoteDesktop); remoteDesktop.BringToFront(); })); }, ()=> { BeginInvoke((MethodInvoker)( () => {// Guna.UI2.WinForms.Guna2Button btnTab = new Guna.UI2.WinForms.Guna2Button { Dock = DockStyle.Left, FillColor = System.Drawing.Color.FromArgb(139, 152, 166), BackColor = System.Drawing.Color.FromArgb(139, 152, 166), Text = $"{shop},{pc}", Tag = $"{shop},{pc}", Font = new System.Drawing.Font(Font.FontFamily, 10, System.Drawing.FontStyle.Bold), BorderColor = System.Drawing.Color.DimGray, BorderThickness = 1 }; btnTab.Click += tab_Click;//При нажатии контрол VNC-клиента выводится на передний план btnTab.MouseClick += tab_Click_Right; //Если нажата средняя кнопка мыши, то окно закрывается(Тут и нужно организовать освобождение всех ресурсов(SSH и VNC)) pnlTabs.Controls.Add(btnTab); })); }); }[/spoiler]
[spoiler title="Так выглядит метод обработки нажатия средней кнопки мыши"]private void tab_Click_Right(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Middle) {//Пока разделил на два цикла для наглядности Parallel.Invoke( ()=> { BeginInvoke((MethodInvoker)( () => { foreach (VncSharp.RemoteDesktop rd in pnlMain.Controls.OfType<VncSharp.RemoteDesktop>()) { if (rd.Tag.ToString() == ((Control)sender).Tag.ToString()) { rd.Disconnect(); rd.Dispose(); pnlMain.Controls.Remove(rd); return; } } })); }, ()=> { BeginInvoke((MethodInvoker)( () => { foreach (Guna.UI2.WinForms.Guna2Button btn in pnlTabs.Controls.OfType<Guna.UI2.WinForms.Guna2Button>()) { if (btn.Tag.ToString() == ((Control)sender).Tag.ToString()) { btn.Dispose(); pnlTabs.Controls.Remove(btn); return; } } })); }); }[/spoiler]
[spoiler title="Ну и сами методы запуска задачи"]private void btnVNC_Click(object sender, EventArgs e) {//Если уже есть вкладка с таким именем, то не подключаемся(в дальнейшем вывести на передний план) foreach (Guna.UI2.WinForms.Guna2Button btn in pnlTabs.Controls.OfType<Guna.UI2.WinForms.Guna2Button>()) if (btn.Text.ToString() == $"{cbShopList.Text},{cbCashList.Text}") return; if (cbShopList.Text == "Магазин:") return; //BeginInvoke((MethodInvoker)(() => VNCConnect(cbShopList.Text, cbCashList.Text))); AsyncVNCConnect(); } private async void AsyncVNCConnect() { await Task.Run( () => { BeginInvoke((MethodInvoker)( () => { VNCConnect(cbShopList.Text, cbCashList.Text); })); }); }[/spoiler]
Всем здравствуйте. Прошу помощи для выхода из тупика. Суть его вот в чем. Я пишу VNC-клиен, однако топология сети такая, что приходится сначала пробрасывать порт через SSH, а уже потом подсоединяться к локалхосту. Для VNC я использую библиотеку vncsharp, а для SSH - Renci.sshnet. В потоке я запускаю метот, который одновременно рисует контролы, создает соединение SSH и VNC. Как теперь залезть в этот поток(или грохнуть его вовсе), чтоб отсоединиться от SSH и освободить порт. От VNC я освобождаюсь перебирая контролы в панеле на форме и сравниваю их тэги, но у ssh нет контрола, по этому такой вопрос. Может я туплю и подход неверный?
private void VNCConnect(string shop, string pc)
{
VncSharp.RemoteDesktop remoteDesktop = new VncSharp.RemoteDesktop();
Parallel.Invoke(
()=>
{
BeginInvoke((MethodInvoker)(
() =>
{
GetShopSettings(shop, pc, out string IPSSH, out string IPConnect, out string SSHLogin, out string SSHPass, out string VNCPass);//Тут я выполняю SQL процедурку и получаю настройки ПК к которому буду подключаться
if (IPSSH != "" && IPConnect != "")
{
AuthenticationMethod auth = new PasswordAuthenticationMethod(SSHLogin, SSHPass);
ConnectionInfo coninfo = new ConnectionInfo(IPSSH, 22, SSHLogin, sysips.Contains(IPConnect.Substring(0, IPConnect.LastIndexOf("."))) ? ProxyTypes.None : ProxyTypes.Http, "IP-proxy", 3128, "login", "pass", auth);//Если я нахожусь в одной подсети с хостом, к которому подключаюсь, но не использовать прокси, иначе использовать
SshClient sshclient = PingHost(IPSSH) ? new SshClient(IPSSH, 22, SSHLogin, SSHPass) : new SshClient(coninfo); // Если конечный хост пингуется, то подключиться без прокси, иначе через предыдущий метод(Сильно замудрено, в дальнейшем упростить)
try
{
sshclient.Connect();
}
catch (Exception ex)
{
if (sysips.Contains("10.21."))
{
if (PingHost("10.21.200.52"))//Если я в одной подсети с прокси-сервером и он пингуется, то хост недоступен
frmMessageBox.Show("Не могу подключиться к хосту", "Хост недоступен \n" + ex.Message, "important"); //Создал кастомную форму с классом Show
else
frmMessageBox.Show("Не могу подключиться к прокси", "Прокси-сервер недоступен \n" + ex.Message, "important");
}
frmMessageBox.Show("Не могу подключиться к хосту", "Хост недоступен \n" + ex.Message, "important");
return;
}
int tunelport = 5900;
while (tunelport < 5950)//Пробую пробросить порт VNC, если не получается - инкрементирую порт на 1 и пробую повторно
{
var portvnc = new ForwardedPortLocal("127.0.0.1", (uint)tunelport, "127.0.0.1", 5900);
sshclient.AddForwardedPort(portvnc);
try
{
portvnc.Start();
break;
}
catch (Exception)
{
sshclient.RemoveForwardedPort(portvnc);
portvnc.Dispose();
tunelport++;
}
if (tunelport == 5950)
{
frmMessageBox.Show("Не могу подключиться", "К сожалению все порты заняты.\n" +
"Попробуйте закрыть одно из соединений к этому магазину", "info");
return;
}
}
remoteDesktop.GetPassword = new VncSharp.AuthenticateDelegate(() => VNCPass);
remoteDesktop.VncPort = tunelport;
remoteDesktop.Connect("127.0.0.1", false, true);//Порт проброшен - подключаемся к себе через проброшеный порт
}
}));
},
()=>
{//Рисую VNC клиент
BeginInvoke((MethodInvoker)(
() =>
{
remoteDesktop.Dock = DockStyle.Fill;
remoteDesktop.Tag = $"{shop},{pc}";
pnlMain.Controls.Add(remoteDesktop);
remoteDesktop.BringToFront();
}));
},
()=>
{
BeginInvoke((MethodInvoker)(
() =>
{//
Guna.UI2.WinForms.Guna2Button btnTab = new Guna.UI2.WinForms.Guna2Button
{
Dock = DockStyle.Left,
FillColor = System.Drawing.Color.FromArgb(139, 152, 166),
BackColor = System.Drawing.Color.FromArgb(139, 152, 166),
Text = $"{shop},{pc}",
Tag = $"{shop},{pc}",
Font = new System.Drawing.Font(Font.FontFamily, 10, System.Drawing.FontStyle.Bold),
BorderColor = System.Drawing.Color.DimGray,
BorderThickness = 1
};
btnTab.Click += tab_Click;//При нажатии контрол VNC-клиента выводится на передний план
btnTab.MouseClick += tab_Click_Right; //Если нажата средняя кнопка мыши, то окно закрывается(Тут и нужно организовать освобождение всех ресурсов(SSH и VNC))
pnlTabs.Controls.Add(btnTab);
}));
});
}
private void tab_Click_Right(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Middle)
{//Пока разделил на два цикла для наглядности
Parallel.Invoke(
()=>
{
BeginInvoke((MethodInvoker)(
() =>
{
foreach (VncSharp.RemoteDesktop rd in pnlMain.Controls.OfType<VncSharp.RemoteDesktop>())
{
if (rd.Tag.ToString() == ((Control)sender).Tag.ToString())
{
rd.Disconnect();
rd.Dispose();
pnlMain.Controls.Remove(rd);
return;
}
}
}));
},
()=>
{
BeginInvoke((MethodInvoker)(
() =>
{
foreach (Guna.UI2.WinForms.Guna2Button btn in pnlTabs.Controls.OfType<Guna.UI2.WinForms.Guna2Button>())
{
if (btn.Tag.ToString() == ((Control)sender).Tag.ToString())
{
btn.Dispose();
pnlTabs.Controls.Remove(btn);
return;
}
}
}));
});
}
private void btnVNC_Click(object sender, EventArgs e)
{//Если уже есть вкладка с таким именем, то не подключаемся(в дальнейшем вывести на передний план)
foreach (Guna.UI2.WinForms.Guna2Button btn in pnlTabs.Controls.OfType<Guna.UI2.WinForms.Guna2Button>())
if (btn.Text.ToString() == $"{cbShopList.Text},{cbCashList.Text}")
return;
if (cbShopList.Text == "Магазин:")
return;
//BeginInvoke((MethodInvoker)(() => VNCConnect(cbShopList.Text, cbCashList.Text)));
AsyncVNCConnect();
}
private async void AsyncVNCConnect()
{
await Task.Run(
() =>
{
BeginInvoke((MethodInvoker)(
() =>
{
VNCConnect(cbShopList.Text, cbCashList.Text);
}));
});
}