翼度科技»论坛 编程开发 .net 查看内容

Web SSH 的原理与在 ASP.NET Core SignalR 中的实现

7

主题

7

帖子

21

积分

新手上路

Rank: 1

积分
21
前言

有个项目,需要在前端有个管理终端可以 SSH 到主控机的终端,如果不考虑用户使用 vim 等需要在控制台内现实界面的软件的话,其实使用 Process 类型去启动相应程序就够了。而这次的需求则需要考虑用户会做相关设置。
原理

这里用到的原理是伪终端。伪终端(pseudo terminal)是现代操作系统的一个功能,他会模拟一对输入输出设备来模拟终端环境去执行相应的进程。伪终端通常会给相应的进程提供例如环境变量或文件等来告知他在终端中运行,这样像 vim 这样的程序可以在最后一行输出命令菜单或者像 npm / pip 这样的程序可以打印炫酷的进度条。通常在我们直接创建子进程的时候,在 Linux 上系统自带了 openpty 方法可以打开伪终端,而在 Windows 上则等到 Windows Terminal 推出后才出现了真正的系统级伪终端。下面付一张来自微软博客的伪终端原理图,Linux 上的原理与之类似。

基本设计

建立连接与监听终端输出


监听前端输入

graph TD;<template>
  
</template>A[终端窗口收到键盘事件] --> B[SignalR 发送请求];<template>
  
</template>B --> C[后台转发到对应终端]超时与关闭

graph TD;<template>
  
</template>A[当 SignalR 发送断开连接或终端超时] --> B[关闭终端进程];依赖库

portable_pty

这里用到这个 Rust 库来建立终端,这个库是一个独立的进程,每次建立连接都会运行。这里当初考虑过直接在 ASP.NET Core 应用里调用 vs-pty(微软开发的,用在 vs 里的库,可以直接在 vs 安装位置复制一份),但是 vs-pty 因为种种原因在 .NET 7 + Ubuntu 22.04 的环境下运行不起来故放弃了。
xterm.js

这个是前端展示终端界面用的库,据说 vs code 也在用这个库,虽然文档不多,但是用起来真的很简单。
SignalR

这个不多说了,咱 .NET 系列 Web 实时通信选他就没错。
代码

废话不多讲了,咱还是直接看代码吧,这里代码还是比较长的,我节选了一些必要的代码。具体 SignalR 之类的配置,还请读者自行参考微软官方文档。

  • main.rs 这个 Rust 代码用于建立伪终端并和 .NET 服务通信,这里使用了最简单的 UDP 方式通信。
  1. use portable_pty::{self, native_pty_system, CommandBuilder, PtySize};
  2. use std::{io::prelude::*, sync::Arc};
  3. use tokio::net::UdpSocket;
  4. #[tokio::main(flavor = "multi_thread", worker_threads = 4)]
  5. async fn main() -> Result<(), Box<dyn std::error::Error>> {
  6. <template>
  7.   
  8. </template><template>
  9.   
  10. </template>let args = std::env::args().collect::<Vec<_>>();
  11. <template>
  12.   
  13. </template><template>
  14.   
  15. </template>// 启动一个终端
  16. <template>
  17.   
  18. </template><template>
  19.   
  20. </template>let pty_pair = native_pty_system().openpty(PtySize {
  21. <template>
  22.   
  23. </template><template>
  24.   
  25. </template><template>
  26.   
  27. </template><template>
  28.   
  29. </template>rows: args.get(2).ok_or("NoNumber")?.parse()?,
  30. <template>
  31.   
  32. </template><template>
  33.   
  34. </template><template>
  35.   
  36. </template><template>
  37.   
  38. </template>cols: args.get(3).ok_or("NoNumber")?.parse()?,
  39. <template>
  40.   
  41. </template><template>
  42.   
  43. </template><template>
  44.   
  45. </template><template>
  46.   
  47. </template>pixel_width: 0,
  48. <template>
  49.   
  50. </template><template>
  51.   
  52. </template><template>
  53.   
  54. </template><template>
  55.   
  56. </template>pixel_height: 0,
  57. <template>
  58.   
  59. </template><template>
  60.   
  61. </template>})?;
  62. <template>
  63.   
  64. </template><template>
  65.   
  66. </template>// 执行传进来的命令
  67. <template>
  68.   
  69. </template><template>
  70.   
  71. </template>let mut cmd = CommandBuilder::new(args.get(4).unwrap_or(&"bash".to_string()));
  72. <template>
  73.   
  74. </template><template>
  75.   
  76. </template>if args.len() > 5 {
  77. <template>
  78.   
  79. </template><template>
  80.   
  81. </template><template>
  82.   
  83. </template><template>
  84.   
  85. </template>cmd.args(&args[5..]);
  86. <template>
  87.   
  88. </template><template>
  89.   
  90. </template>}
  91. <template>
  92.   
  93. </template><template>
  94.   
  95. </template>let mut proc = pty_pair.slave.spawn_command(cmd)?;
  96. <template>
  97.   
  98. </template><template>
  99.   
  100. </template>// 绑定输入输出
  101. <template>
  102.   
  103. </template><template>
  104.   
  105. </template>let mut reader = pty_pair.master.try_clone_reader()?;
  106. <template>
  107.   
  108. </template><template>
  109.   
  110. </template>let mut writer = pty_pair.master.take_writer()?;
  111. <template>
  112.   
  113. </template><template>
  114.   
  115. </template>// 绑定网络
  116. <template>
  117.   
  118. </template><template>
  119.   
  120. </template>let main_socket = Arc::new(UdpSocket::bind("localhost:0").await?);
  121. <template>
  122.   
  123. </template><template>
  124.   
  125. </template>let recv_socket = main_socket.clone();
  126. <template>
  127.   
  128. </template><template>
  129.   
  130. </template>let send_socket = main_socket.clone();
  131. <template>
  132.   
  133. </template><template>
  134.   
  135. </template>let resize_socket = UdpSocket::bind("localhost:0").await?;
  136. <template>
  137.   
  138. </template><template>
  139.   
  140. </template>// 连接到主服务后发送地址
  141. <template>
  142.   
  143. </template><template>
  144.   
  145. </template>main_socket
  146. <template>
  147.   
  148. </template><template>
  149.   
  150. </template><template>
  151.   
  152. </template><template>
  153.   
  154. </template>.connect(args.get(1).ok_or("NoSuchAddr")?)
  155. <template>
  156.   
  157. </template><template>
  158.   
  159. </template><template>
  160.   
  161. </template><template>
  162.   
  163. </template>.await?;
  164. <template>
  165.   
  166. </template><template>
  167.   
  168. </template>main_socket
  169. <template>
  170.   
  171. </template><template>
  172.   
  173. </template><template>
  174.   
  175. </template><template>
  176.   
  177. </template>.send(&serde_json::to_vec(&ClientAddr {
  178. <template>
  179.   
  180. </template><template>
  181.   
  182. </template><template>
  183.   
  184. </template><template>
  185.   
  186. </template><template>
  187.   
  188. </template><template>
  189.   
  190. </template>main: main_socket.local_addr()?.to_string(),
  191. <template>
  192.   
  193. </template><template>
  194.   
  195. </template><template>
  196.   
  197. </template><template>
  198.   
  199. </template><template>
  200.   
  201. </template><template>
  202.   
  203. </template>resize: resize_socket.local_addr()?.to_string(),
  204. <template>
  205.   
  206. </template><template>
  207.   
  208. </template><template>
  209.   
  210. </template><template>
  211.   
  212. </template>})?)
  213. <template>
  214.   
  215. </template><template>
  216.   
  217. </template><template>
  218.   
  219. </template><template>
  220.   
  221. </template>.await?;
  222. <template>
  223.   
  224. </template><template>
  225.   
  226. </template>// 读取终端数据并发送
  227. <template>
  228.   
  229. </template><template>
  230.   
  231. </template>let read = tokio::spawn(async move {
  232. <template>
  233.   
  234. </template><template>
  235.   
  236. </template><template>
  237.   
  238. </template><template>
  239.   
  240. </template>loop {
  241. <template>
  242.   
  243. </template><template>
  244.   
  245. </template><template>
  246.   
  247. </template><template>
  248.   
  249. </template><template>
  250.   
  251. </template><template>
  252.   
  253. </template>let mut buf = [0; 1024];
  254. <template>
  255.   
  256. </template><template>
  257.   
  258. </template><template>
  259.   
  260. </template><template>
  261.   
  262. </template><template>
  263.   
  264. </template><template>
  265.   
  266. </template>let n = reader.read(&mut buf).unwrap();
  267. <template>
  268.   
  269. </template><template>
  270.   
  271. </template><template>
  272.   
  273. </template><template>
  274.   
  275. </template><template>
  276.   
  277. </template><template>
  278.   
  279. </template>if n == 0 {
  280. <template>
  281.   
  282. </template><template>
  283.   
  284. </template><template>
  285.   
  286. </template><template>
  287.   
  288. </template><template>
  289.   
  290. </template><template>
  291.   
  292. </template><template>
  293.   
  294. </template><template>
  295.   
  296. </template>continue;
  297. <template>
  298.   
  299. </template><template>
  300.   
  301. </template><template>
  302.   
  303. </template><template>
  304.   
  305. </template><template>
  306.   
  307. </template><template>
  308.   
  309. </template>}
  310. <template>
  311.   
  312. </template><template>
  313.   
  314. </template><template>
  315.   
  316. </template><template>
  317.   
  318. </template><template>
  319.   
  320. </template><template>
  321.   
  322. </template>println!("{:?}", &buf[..n]);
  323. <template>
  324.   
  325. </template><template>
  326.   
  327. </template><template>
  328.   
  329. </template><template>
  330.   
  331. </template><template>
  332.   
  333. </template><template>
  334.   
  335. </template>send_socket.send(&buf[..n]).await.unwrap();
  336. <template>
  337.   
  338. </template><template>
  339.   
  340. </template><template>
  341.   
  342. </template><template>
  343.   
  344. </template>}
  345. <template>
  346.   
  347. </template><template>
  348.   
  349. </template>});
  350. <template>
  351.   
  352. </template><template>
  353.   
  354. </template>// 接收数据并写入终端
  355. <template>
  356.   
  357. </template><template>
  358.   
  359. </template>let write = tokio::spawn(async move {
  360. <template>
  361.   
  362. </template><template>
  363.   
  364. </template><template>
  365.   
  366. </template><template>
  367.   
  368. </template>loop {
  369. <template>
  370.   
  371. </template><template>
  372.   
  373. </template><template>
  374.   
  375. </template><template>
  376.   
  377. </template><template>
  378.   
  379. </template><template>
  380.   
  381. </template>let mut buf = [0; 1024];
  382. <template>
  383.   
  384. </template><template>
  385.   
  386. </template><template>
  387.   
  388. </template><template>
  389.   
  390. </template><template>
  391.   
  392. </template><template>
  393.   
  394. </template>let n = recv_socket.recv(&mut buf).await.unwrap();
  395. <template>
  396.   
  397. </template><template>
  398.   
  399. </template><template>
  400.   
  401. </template><template>
  402.   
  403. </template><template>
  404.   
  405. </template><template>
  406.   
  407. </template>if n == 0 {
  408. <template>
  409.   
  410. </template><template>
  411.   
  412. </template><template>
  413.   
  414. </template><template>
  415.   
  416. </template><template>
  417.   
  418. </template><template>
  419.   
  420. </template><template>
  421.   
  422. </template><template>
  423.   
  424. </template>continue;
  425. <template>
  426.   
  427. </template><template>
  428.   
  429. </template><template>
  430.   
  431. </template><template>
  432.   
  433. </template><template>
  434.   
  435. </template><template>
  436.   
  437. </template>}
  438. <template>
  439.   
  440. </template><template>
  441.   
  442. </template><template>
  443.   
  444. </template><template>
  445.   
  446. </template><template>
  447.   
  448. </template><template>
  449.   
  450. </template>println!("{:?}", &buf[..n]);
  451. <template>
  452.   
  453. </template><template>
  454.   
  455. </template><template>
  456.   
  457. </template><template>
  458.   
  459. </template><template>
  460.   
  461. </template><template>
  462.   
  463. </template>writer.write_all(&buf[..n]).unwrap();
  464. <template>
  465.   
  466. </template><template>
  467.   
  468. </template><template>
  469.   
  470. </template><template>
  471.   
  472. </template>}
  473. <template>
  474.   
  475. </template><template>
  476.   
  477. </template>});
  478. <template>
  479.   
  480. </template><template>
  481.   
  482. </template>// 接收调整窗口大小的数据
  483. <template>
  484.   
  485. </template><template>
  486.   
  487. </template>let resize = tokio::spawn(async move {
  488. <template>
  489.   
  490. </template><template>
  491.   
  492. </template><template>
  493.   
  494. </template><template>
  495.   
  496. </template>let mut buf = [0; 1024];
  497. <template>
  498.   
  499. </template><template>
  500.   
  501. </template><template>
  502.   
  503. </template><template>
  504.   
  505. </template>loop {
  506. <template>
  507.   
  508. </template><template>
  509.   
  510. </template><template>
  511.   
  512. </template><template>
  513.   
  514. </template><template>
  515.   
  516. </template><template>
  517.   
  518. </template>let n = resize_socket.recv(&mut buf).await.unwrap();
  519. <template>
  520.   
  521. </template><template>
  522.   
  523. </template><template>
  524.   
  525. </template><template>
  526.   
  527. </template><template>
  528.   
  529. </template><template>
  530.   
  531. </template>if n == 0 {
  532. <template>
  533.   
  534. </template><template>
  535.   
  536. </template><template>
  537.   
  538. </template><template>
  539.   
  540. </template><template>
  541.   
  542. </template><template>
  543.   
  544. </template><template>
  545.   
  546. </template><template>
  547.   
  548. </template>continue;
  549. <template>
  550.   
  551. </template><template>
  552.   
  553. </template><template>
  554.   
  555. </template><template>
  556.   
  557. </template><template>
  558.   
  559. </template><template>
  560.   
  561. </template>}
  562. <template>
  563.   
  564. </template><template>
  565.   
  566. </template><template>
  567.   
  568. </template><template>
  569.   
  570. </template><template>
  571.   
  572. </template><template>
  573.   
  574. </template>let size: WinSize = serde_json::from_slice(buf[..n].as_ref()).unwrap();
  575. <template>
  576.   
  577. </template><template>
  578.   
  579. </template><template>
  580.   
  581. </template><template>
  582.   
  583. </template><template>
  584.   
  585. </template><template>
  586.   
  587. </template>pty_pair
  588. <template>
  589.   
  590. </template><template>
  591.   
  592. </template><template>
  593.   
  594. </template><template>
  595.   
  596. </template><template>
  597.   
  598. </template><template>
  599.   
  600. </template><template>
  601.   
  602. </template><template>
  603.   
  604. </template>.master
  605. <template>
  606.   
  607. </template><template>
  608.   
  609. </template><template>
  610.   
  611. </template><template>
  612.   
  613. </template><template>
  614.   
  615. </template><template>
  616.   
  617. </template><template>
  618.   
  619. </template><template>
  620.   
  621. </template>.resize(PtySize {
  622. <template>
  623.   
  624. </template><template>
  625.   
  626. </template><template>
  627.   
  628. </template><template>
  629.   
  630. </template><template>
  631.   
  632. </template><template>
  633.   
  634. </template><template>
  635.   
  636. </template><template>
  637.   
  638. </template><template>
  639.   
  640. </template><template>
  641.   
  642. </template>rows: size.rows,
  643. <template>
  644.   
  645. </template><template>
  646.   
  647. </template><template>
  648.   
  649. </template><template>
  650.   
  651. </template><template>
  652.   
  653. </template><template>
  654.   
  655. </template><template>
  656.   
  657. </template><template>
  658.   
  659. </template><template>
  660.   
  661. </template><template>
  662.   
  663. </template>cols: size.cols,
  664. <template>
  665.   
  666. </template><template>
  667.   
  668. </template><template>
  669.   
  670. </template><template>
  671.   
  672. </template><template>
  673.   
  674. </template><template>
  675.   
  676. </template><template>
  677.   
  678. </template><template>
  679.   
  680. </template><template>
  681.   
  682. </template><template>
  683.   
  684. </template>pixel_width: 0,
  685. <template>
  686.   
  687. </template><template>
  688.   
  689. </template><template>
  690.   
  691. </template><template>
  692.   
  693. </template><template>
  694.   
  695. </template><template>
  696.   
  697. </template><template>
  698.   
  699. </template><template>
  700.   
  701. </template><template>
  702.   
  703. </template><template>
  704.   
  705. </template>pixel_height: 0,
  706. <template>
  707.   
  708. </template><template>
  709.   
  710. </template><template>
  711.   
  712. </template><template>
  713.   
  714. </template><template>
  715.   
  716. </template><template>
  717.   
  718. </template><template>
  719.   
  720. </template><template>
  721.   
  722. </template>})
  723. <template>
  724.   
  725. </template><template>
  726.   
  727. </template><template>
  728.   
  729. </template><template>
  730.   
  731. </template><template>
  732.   
  733. </template><template>
  734.   
  735. </template><template>
  736.   
  737. </template><template>
  738.   
  739. </template>.unwrap();
  740. <template>
  741.   
  742. </template><template>
  743.   
  744. </template><template>
  745.   
  746. </template><template>
  747.   
  748. </template>}
  749. <template>
  750.   
  751. </template><template>
  752.   
  753. </template>});
  754. <template>
  755.   
  756. </template><template>
  757.   
  758. </template>// 等待进程结束
  759. <template>
  760.   
  761. </template><template>
  762.   
  763. </template>let result = proc.wait()?;
  764. <template>
  765.   
  766. </template><template>
  767.   
  768. </template>write.abort();
  769. <template>
  770.   
  771. </template><template>
  772.   
  773. </template>read.abort();
  774. <template>
  775.   
  776. </template><template>
  777.   
  778. </template>resize.abort();
  779. <template>
  780.   
  781. </template><template>
  782.   
  783. </template>if 0 == result.exit_code() {
  784. <template>
  785.   
  786. </template><template>
  787.   
  788. </template><template>
  789.   
  790. </template><template>
  791.   
  792. </template>std::process::exit(result.exit_code() as i32);
  793. <template>
  794.   
  795. </template><template>
  796.   
  797. </template>}
  798. <template>
  799.   
  800. </template><template>
  801.   
  802. </template>return Ok(());
  803. }
  804. /// 窗口大小
  805. #[derive(serde::Deserialize)]
  806. struct WinSize {
  807. <template>
  808.   
  809. </template><template>
  810.   
  811. </template>/// 行数
  812. <template>
  813.   
  814. </template><template>
  815.   
  816. </template>rows: u16,
  817. <template>
  818.   
  819. </template><template>
  820.   
  821. </template>/// 列数
  822. <template>
  823.   
  824. </template><template>
  825.   
  826. </template>cols: u16,
  827. }
  828. /// 客户端地址
  829. #[derive(serde::Serialize)]
  830. struct ClientAddr {
  831. <template>
  832.   
  833. </template><template>
  834.   
  835. </template>/// 主要地址
  836. <template>
  837.   
  838. </template><template>
  839.   
  840. </template>main: String,
  841. <template>
  842.   
  843. </template><template>
  844.   
  845. </template>/// 调整窗口大小地址
  846. <template>
  847.   
  848. </template><template>
  849.   
  850. </template>resize: String,
  851. }
复制代码

  • SshPtyConnection.cs 这个代码用于维持一个后台运行的 Rust 进程,并管理他的双向通信。
  1. <template>
  2.   
  3. </template><template>
  4.   
  5. </template>public class SshPtyConnection : IDisposable
  6. <template>
  7.   
  8. </template><template>
  9.   
  10. </template>{
  11. <template>
  12.   
  13. </template><template>
  14.   
  15. </template><template>
  16.   
  17. </template><template>
  18.   
  19. </template>/// <summary>
  20. <template>
  21.   
  22. </template><template>
  23.   
  24. </template><template>
  25.   
  26. </template><template>
  27.   
  28. </template>/// 客户端地址
  29. <template>
  30.   
  31. </template><template>
  32.   
  33. </template><template>
  34.   
  35. </template><template>
  36.   
  37. </template>/// </summary>
  38. <template>
  39.   
  40. </template><template>
  41.   
  42. </template><template>
  43.   
  44. </template><template>
  45.   
  46. </template>private class ClientEndPoint
  47. <template>
  48.   
  49. </template><template>
  50.   
  51. </template><template>
  52.   
  53. </template><template>
  54.   
  55. </template>{
  56. <template>
  57.   
  58. </template><template>
  59.   
  60. </template><template>
  61.   
  62. </template><template>
  63.   
  64. </template><template>
  65.   
  66. </template><template>
  67.   
  68. </template>public required string Main { get; set; }
  69. <template>
  70.   
  71. </template><template>
  72.   
  73. </template><template>
  74.   
  75. </template><template>
  76.   
  77. </template><template>
  78.   
  79. </template><template>
  80.   
  81. </template>public required string Resize { get; set; }
  82. <template>
  83.   
  84. </template><template>
  85.   
  86. </template><template>
  87.   
  88. </template><template>
  89.   
  90. </template>}
  91. <template>
  92.   
  93. </template><template>
  94.   
  95. </template><template>
  96.   
  97. </template><template>
  98.   
  99. </template>/// <summary>
  100. <template>
  101.   
  102. </template><template>
  103.   
  104. </template><template>
  105.   
  106. </template><template>
  107.   
  108. </template>/// 窗口大小
  109. <template>
  110.   
  111. </template><template>
  112.   
  113. </template><template>
  114.   
  115. </template><template>
  116.   
  117. </template>/// </summary>
  118. <template>
  119.   
  120. </template><template>
  121.   
  122. </template><template>
  123.   
  124. </template><template>
  125.   
  126. </template>private class WinSize
  127. <template>
  128.   
  129. </template><template>
  130.   
  131. </template><template>
  132.   
  133. </template><template>
  134.   
  135. </template>{
  136. <template>
  137.   
  138. </template><template>
  139.   
  140. </template><template>
  141.   
  142. </template><template>
  143.   
  144. </template><template>
  145.   
  146. </template><template>
  147.   
  148. </template>public int Cols { get; set; }
  149. <template>
  150.   
  151. </template><template>
  152.   
  153. </template><template>
  154.   
  155. </template><template>
  156.   
  157. </template><template>
  158.   
  159. </template><template>
  160.   
  161. </template>public int Rows { get; set; }
  162. <template>
  163.   
  164. </template><template>
  165.   
  166. </template><template>
  167.   
  168. </template><template>
  169.   
  170. </template>}
  171. <template>
  172.   
  173. </template><template>
  174.   
  175. </template><template>
  176.   
  177. </template><template>
  178.   
  179. </template>/// <summary>
  180. <template>
  181.   
  182. </template><template>
  183.   
  184. </template><template>
  185.   
  186. </template><template>
  187.   
  188. </template>/// SignalR 上下文
  189. <template>
  190.   
  191. </template><template>
  192.   
  193. </template><template>
  194.   
  195. </template><template>
  196.   
  197. </template>/// </summary>
  198. <template>
  199.   
  200. </template><template>
  201.   
  202. </template><template>
  203.   
  204. </template><template>
  205.   
  206. </template>private readonly IHubContext<SshHub> _hubContext;
  207. <template>
  208.   
  209. </template><template>
  210.   
  211. </template><template>
  212.   
  213. </template><template>
  214.   
  215. </template>/// <summary>
  216. <template>
  217.   
  218. </template><template>
  219.   
  220. </template><template>
  221.   
  222. </template><template>
  223.   
  224. </template>/// 日志记录器
  225. <template>
  226.   
  227. </template><template>
  228.   
  229. </template><template>
  230.   
  231. </template><template>
  232.   
  233. </template>/// </summary>
  234. <template>
  235.   
  236. </template><template>
  237.   
  238. </template><template>
  239.   
  240. </template><template>
  241.   
  242. </template>private readonly ILogger<SshPtyConnection> _logger;
  243. <template>
  244.   
  245. </template><template>
  246.   
  247. </template><template>
  248.   
  249. </template><template>
  250.   
  251. </template>/// <summary>
  252. <template>
  253.   
  254. </template><template>
  255.   
  256. </template><template>
  257.   
  258. </template><template>
  259.   
  260. </template>/// UDP 客户端
  261. <template>
  262.   
  263. </template><template>
  264.   
  265. </template><template>
  266.   
  267. </template><template>
  268.   
  269. </template>/// </summary>
  270. <template>
  271.   
  272. </template><template>
  273.   
  274. </template><template>
  275.   
  276. </template><template>
  277.   
  278. </template>private readonly UdpClient udpClient;
  279. <template>
  280.   
  281. </template><template>
  282.   
  283. </template><template>
  284.   
  285. </template><template>
  286.   
  287. </template>/// <summary>
  288. <template>
  289.   
  290. </template><template>
  291.   
  292. </template><template>
  293.   
  294. </template><template>
  295.   
  296. </template>/// 最后活动时间
  297. <template>
  298.   
  299. </template><template>
  300.   
  301. </template><template>
  302.   
  303. </template><template>
  304.   
  305. </template>/// </summary>
  306. <template>
  307.   
  308. </template><template>
  309.   
  310. </template><template>
  311.   
  312. </template><template>
  313.   
  314. </template>private DateTime lastActivity = DateTime.UtcNow;
  315. <template>
  316.   
  317. </template><template>
  318.   
  319. </template><template>
  320.   
  321. </template><template>
  322.   
  323. </template>/// <summary>
  324. <template>
  325.   
  326. </template><template>
  327.   
  328. </template><template>
  329.   
  330. </template><template>
  331.   
  332. </template>/// 是否已释放
  333. <template>
  334.   
  335. </template><template>
  336.   
  337. </template><template>
  338.   
  339. </template><template>
  340.   
  341. </template>/// </summary>
  342. <template>
  343.   
  344. </template><template>
  345.   
  346. </template><template>
  347.   
  348. </template><template>
  349.   
  350. </template>private bool disposedValue;
  351. <template>
  352.   
  353. </template><template>
  354.   
  355. </template><template>
  356.   
  357. </template><template>
  358.   
  359. </template>/// <summary>
  360. <template>
  361.   
  362. </template><template>
  363.   
  364. </template><template>
  365.   
  366. </template><template>
  367.   
  368. </template>/// 是否已释放
  369. <template>
  370.   
  371. </template><template>
  372.   
  373. </template><template>
  374.   
  375. </template><template>
  376.   
  377. </template>/// </summary>
  378. <template>
  379.   
  380. </template><template>
  381.   
  382. </template><template>
  383.   
  384. </template><template>
  385.   
  386. </template>public bool IsDisposed => disposedValue;
  387. <template>
  388.   
  389. </template><template>
  390.   
  391. </template><template>
  392.   
  393. </template><template>
  394.   
  395. </template>/// <summary>
  396. <template>
  397.   
  398. </template><template>
  399.   
  400. </template><template>
  401.   
  402. </template><template>
  403.   
  404. </template>/// 最后活动时间
  405. <template>
  406.   
  407. </template><template>
  408.   
  409. </template><template>
  410.   
  411. </template><template>
  412.   
  413. </template>/// </summary>
  414. <template>
  415.   
  416. </template><template>
  417.   
  418. </template><template>
  419.   
  420. </template><template>
  421.   
  422. </template>public DateTime LastActivity => lastActivity;
  423. <template>
  424.   
  425. </template><template>
  426.   
  427. </template><template>
  428.   
  429. </template><template>
  430.   
  431. </template>/// <summary>
  432. <template>
  433.   
  434. </template><template>
  435.   
  436. </template><template>
  437.   
  438. </template><template>
  439.   
  440. </template>/// 取消令牌
  441. <template>
  442.   
  443. </template><template>
  444.   
  445. </template><template>
  446.   
  447. </template><template>
  448.   
  449. </template>/// </summary>
  450. <template>
  451.   
  452. </template><template>
  453.   
  454. </template><template>
  455.   
  456. </template><template>
  457.   
  458. </template>public CancellationTokenSource CancellationTokenSource { get; } = new CancellationTokenSource();
  459. <template>
  460.   
  461. </template><template>
  462.   
  463. </template><template>
  464.   
  465. </template><template>
  466.   
  467. </template>/// <summary>
  468. <template>
  469.   
  470. </template><template>
  471.   
  472. </template><template>
  473.   
  474. </template><template>
  475.   
  476. </template>/// 窗口大小
  477. <template>
  478.   
  479. </template><template>
  480.   
  481. </template><template>
  482.   
  483. </template><template>
  484.   
  485. </template>/// </summary>
  486. <template>
  487.   
  488. </template><template>
  489.   
  490. </template><template>
  491.   
  492. </template><template>
  493.   
  494. </template>public event EventHandler<EventArgs> Closed = delegate { };
  495. <template>
  496.   
  497. </template><template>
  498.   
  499. </template><template>
  500.   
  501. </template><template>
  502.   
  503. </template>/// <summary>
  504. <template>
  505.   
  506. </template><template>
  507.   
  508. </template><template>
  509.   
  510. </template><template>
  511.   
  512. </template>/// 构造函数
  513. <template>
  514.   
  515. </template><template>
  516.   
  517. </template><template>
  518.   
  519. </template><template>
  520.   
  521. </template>/// </summary>
  522. <template>
  523.   
  524. </template><template>
  525.   
  526. </template><template>
  527.   
  528. </template><template>
  529.   
  530. </template>/// <param name="hubContext"></param>
  531. <template>
  532.   
  533. </template><template>
  534.   
  535. </template><template>
  536.   
  537. </template><template>
  538.   
  539. </template>/// <param name="logger"></param>
  540. <template>
  541.   
  542. </template><template>
  543.   
  544. </template><template>
  545.   
  546. </template><template>
  547.   
  548. </template>/// <exception cref="ArgumentNullException"></exception>
  549. <template>
  550.   
  551. </template><template>
  552.   
  553. </template><template>
  554.   
  555. </template><template>
  556.   
  557. </template>public SshPtyConnection(IHubContext<SshHub> hubContext, ILogger<SshPtyConnection> logger)
  558. <template>
  559.   
  560. </template><template>
  561.   
  562. </template><template>
  563.   
  564. </template><template>
  565.   
  566. </template>{
  567. <template>
  568.   
  569. </template><template>
  570.   
  571. </template><template>
  572.   
  573. </template><template>
  574.   
  575. </template><template>
  576.   
  577. </template><template>
  578.   
  579. </template>_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
  580. <template>
  581.   
  582. </template><template>
  583.   
  584. </template><template>
  585.   
  586. </template><template>
  587.   
  588. </template><template>
  589.   
  590. </template><template>
  591.   
  592. </template>_logger = logger ?? throw new ArgumentNullException(nameof(logger));
  593. <template>
  594.   
  595. </template><template>
  596.   
  597. </template><template>
  598.   
  599. </template><template>
  600.   
  601. </template><template>
  602.   
  603. </template><template>
  604.   
  605. </template>lastActivity = DateTime.Now;
  606. <template>
  607.   
  608. </template><template>
  609.   
  610. </template><template>
  611.   
  612. </template><template>
  613.   
  614. </template><template>
  615.   
  616. </template><template>
  617.   
  618. </template>udpClient = new(IPEndPoint.Parse("127.0.0.1:0"));
  619. <template>
  620.   
  621. </template><template>
  622.   
  623. </template><template>
  624.   
  625. </template><template>
  626.   
  627. </template>}
  628. <template>
  629.   
  630. </template><template>
  631.   
  632. </template><template>
  633.   
  634. </template><template>
  635.   
  636. </template>/// <summary>
  637. <template>
  638.   
  639. </template><template>
  640.   
  641. </template><template>
  642.   
  643. </template><template>
  644.   
  645. </template>/// 开始监听
  646. <template>
  647.   
  648. </template><template>
  649.   
  650. </template><template>
  651.   
  652. </template><template>
  653.   
  654. </template>/// </summary>
  655. <template>
  656.   
  657. </template><template>
  658.   
  659. </template><template>
  660.   
  661. </template><template>
  662.   
  663. </template>/// <param name="connectionId">连接 ID</param>
  664. <template>
  665.   
  666. </template><template>
  667.   
  668. </template><template>
  669.   
  670. </template><template>
  671.   
  672. </template>/// <param name="username">用户名</param>
  673. <template>
  674.   
  675. </template><template>
  676.   
  677. </template><template>
  678.   
  679. </template><template>
  680.   
  681. </template>/// <param name="height">行数</param>
  682. <template>
  683.   
  684. </template><template>
  685.   
  686. </template><template>
  687.   
  688. </template><template>
  689.   
  690. </template>/// <param name="width">列数</param>
  691. <template>
  692.   
  693. </template><template>
  694.   
  695. </template><template>
  696.   
  697. </template><template>
  698.   
  699. </template>public async void StartAsync(string connectionId, string username, int height, int width)
  700. <template>
  701.   
  702. </template><template>
  703.   
  704. </template><template>
  705.   
  706. </template><template>
  707.   
  708. </template>{
  709. <template>
  710.   
  711. </template><template>
  712.   
  713. </template><template>
  714.   
  715. </template><template>
  716.   
  717. </template><template>
  718.   
  719. </template><template>
  720.   
  721. </template>var token = CancellationTokenSource.Token;
  722. <template>
  723.   
  724. </template><template>
  725.   
  726. </template><template>
  727.   
  728. </template><template>
  729.   
  730. </template><template>
  731.   
  732. </template><template>
  733.   
  734. </template>_logger.LogInformation("process starting");
  735. <template>
  736.   
  737. </template><template>
  738.   
  739. </template><template>
  740.   
  741. </template><template>
  742.   
  743. </template><template>
  744.   
  745. </template><template>
  746.   
  747. </template>// 启动进程
  748. <template>
  749.   
  750. </template><template>
  751.   
  752. </template><template>
  753.   
  754. </template><template>
  755.   
  756. </template><template>
  757.   
  758. </template><template>
  759.   
  760. </template>using var process = Process.Start(new ProcessStartInfo
  761. <template>
  762.   
  763. </template><template>
  764.   
  765. </template><template>
  766.   
  767. </template><template>
  768.   
  769. </template><template>
  770.   
  771. </template><template>
  772.   
  773. </template>{
  774. <template>
  775.   
  776. </template><template>
  777.   
  778. </template><template>
  779.   
  780. </template><template>
  781.   
  782. </template><template>
  783.   
  784. </template><template>
  785.   
  786. </template><template>
  787.   
  788. </template><template>
  789.   
  790. </template>FileName = OperatingSystem.IsOSPlatform("windows") ? "PtyWrapper.exe" : "pty-wrapper",
  791. <template>
  792.   
  793. </template><template>
  794.   
  795. </template><template>
  796.   
  797. </template><template>
  798.   
  799. </template><template>
  800.   
  801. </template><template>
  802.   
  803. </template><template>
  804.   
  805. </template><template>
  806.   
  807. </template>// 这里用了 su -l username,因为程序直接部署在主控机的 root 下,所以不需要 ssh 只需要切换用户即可,如果程序部署在其他机器上,需要使用 ssh
  808. <template>
  809.   
  810. </template><template>
  811.   
  812. </template><template>
  813.   
  814. </template><template>
  815.   
  816. </template><template>
  817.   
  818. </template><template>
  819.   
  820. </template><template>
  821.   
  822. </template><template>
  823.   
  824. </template>ArgumentList = { udpClient.Client.LocalEndPoint!.ToString() ?? "127.0.0.1:0", height.ToString(), width.ToString(), "su", "-l", username }
  825. <template>
  826.   
  827. </template><template>
  828.   
  829. </template><template>
  830.   
  831. </template><template>
  832.   
  833. </template><template>
  834.   
  835. </template><template>
  836.   
  837. </template>});
  838. <template>
  839.   
  840. </template><template>
  841.   
  842. </template><template>
  843.   
  844. </template><template>
  845.   
  846. </template><template>
  847.   
  848. </template><template>
  849.   
  850. </template>// 接收客户端地址
  851. <template>
  852.   
  853. </template><template>
  854.   
  855. </template><template>
  856.   
  857. </template><template>
  858.   
  859. </template><template>
  860.   
  861. </template><template>
  862.   
  863. </template>var result = await udpClient.ReceiveAsync();
  864. <template>
  865.   
  866. </template><template>
  867.   
  868. </template><template>
  869.   
  870. </template><template>
  871.   
  872. </template><template>
  873.   
  874. </template><template>
  875.   
  876. </template>var clientEndPoint = await JsonSerializer.DeserializeAsync<ClientEndPoint>(new MemoryStream(result.Buffer), new JsonSerializerOptions
  877. <template>
  878.   
  879. </template><template>
  880.   
  881. </template><template>
  882.   
  883. </template><template>
  884.   
  885. </template><template>
  886.   
  887. </template><template>
  888.   
  889. </template>{
  890. <template>
  891.   
  892. </template><template>
  893.   
  894. </template><template>
  895.   
  896. </template><template>
  897.   
  898. </template><template>
  899.   
  900. </template><template>
  901.   
  902. </template><template>
  903.   
  904. </template><template>
  905.   
  906. </template>PropertyNameCaseInsensitive = true
  907. <template>
  908.   
  909. </template><template>
  910.   
  911. </template><template>
  912.   
  913. </template><template>
  914.   
  915. </template><template>
  916.   
  917. </template><template>
  918.   
  919. </template>});
  920. <template>
  921.   
  922. </template><template>
  923.   
  924. </template><template>
  925.   
  926. </template><template>
  927.   
  928. </template><template>
  929.   
  930. </template><template>
  931.   
  932. </template>if (clientEndPoint == null)
  933. <template>
  934.   
  935. </template><template>
  936.   
  937. </template><template>
  938.   
  939. </template><template>
  940.   
  941. </template><template>
  942.   
  943. </template><template>
  944.   
  945. </template>{
  946. <template>
  947.   
  948. </template><template>
  949.   
  950. </template><template>
  951.   
  952. </template><template>
  953.   
  954. </template><template>
  955.   
  956. </template><template>
  957.   
  958. </template><template>
  959.   
  960. </template><template>
  961.   
  962. </template>CancellationTokenSource.Cancel();
  963. <template>
  964.   
  965. </template><template>
  966.   
  967. </template><template>
  968.   
  969. </template><template>
  970.   
  971. </template><template>
  972.   
  973. </template><template>
  974.   
  975. </template><template>
  976.   
  977. </template><template>
  978.   
  979. </template>return;
  980. <template>
  981.   
  982. </template><template>
  983.   
  984. </template><template>
  985.   
  986. </template><template>
  987.   
  988. </template><template>
  989.   
  990. </template><template>
  991.   
  992. </template>}
  993. <template>
  994.   
  995. </template><template>
  996.   
  997. </template><template>
  998.   
  999. </template><template>
  1000.   
  1001. </template><template>
  1002.   
  1003. </template><template>
  1004.   
  1005. </template>process!.Exited += (_, _) => CancellationTokenSource.Cancel();
  1006. <template>
  1007.   
  1008. </template><template>
  1009.   
  1010. </template><template>
  1011.   
  1012. </template><template>
  1013.   
  1014. </template><template>
  1015.   
  1016. </template><template>
  1017.   
  1018. </template>var remoteEndPoint = IPEndPoint.Parse(clientEndPoint.Main);
  1019. <template>
  1020.   
  1021. </template><template>
  1022.   
  1023. </template><template>
  1024.   
  1025. </template><template>
  1026.   
  1027. </template><template>
  1028.   
  1029. </template><template>
  1030.   
  1031. </template>udpClient.Connect(remoteEndPoint);
  1032. <template>
  1033.   
  1034. </template><template>
  1035.   
  1036. </template><template>
  1037.   
  1038. </template><template>
  1039.   
  1040. </template><template>
  1041.   
  1042. </template><template>
  1043.   
  1044. </template>var stringBuilder = new StringBuilder();
  1045. <template>
  1046.   
  1047. </template><template>
  1048.   
  1049. </template><template>
  1050.   
  1051. </template><template>
  1052.   
  1053. </template><template>
  1054.   
  1055. </template><template>
  1056.   
  1057. </template>// 接收客户端数据,并发送到 SignalR,直到客户端断开连接或者超时 10 分钟
  1058. <template>
  1059.   
  1060. </template><template>
  1061.   
  1062. </template><template>
  1063.   
  1064. </template><template>
  1065.   
  1066. </template><template>
  1067.   
  1068. </template><template>
  1069.   
  1070. </template>while (!token.IsCancellationRequested && lastActivity.AddMinutes(10) > DateTime.Now && !(process?.HasExited ?? false))
  1071. <template>
  1072.   
  1073. </template><template>
  1074.   
  1075. </template><template>
  1076.   
  1077. </template><template>
  1078.   
  1079. </template><template>
  1080.   
  1081. </template><template>
  1082.   
  1083. </template>{
  1084. <template>
  1085.   
  1086. </template><template>
  1087.   
  1088. </template><template>
  1089.   
  1090. </template><template>
  1091.   
  1092. </template><template>
  1093.   
  1094. </template><template>
  1095.   
  1096. </template><template>
  1097.   
  1098. </template><template>
  1099.   
  1100. </template>try
  1101. <template>
  1102.   
  1103. </template><template>
  1104.   
  1105. </template><template>
  1106.   
  1107. </template><template>
  1108.   
  1109. </template><template>
  1110.   
  1111. </template><template>
  1112.   
  1113. </template><template>
  1114.   
  1115. </template><template>
  1116.   
  1117. </template>{
  1118. <template>
  1119.   
  1120. </template><template>
  1121.   
  1122. </template><template>
  1123.   
  1124. </template><template>
  1125.   
  1126. </template><template>
  1127.   
  1128. </template><template>
  1129.   
  1130. </template><template>
  1131.   
  1132. </template><template>
  1133.   
  1134. </template><template>
  1135.   
  1136. </template><template>
  1137.   
  1138. </template>lastActivity = DateTime.Now;
  1139. <template>
  1140.   
  1141. </template><template>
  1142.   
  1143. </template><template>
  1144.   
  1145. </template><template>
  1146.   
  1147. </template><template>
  1148.   
  1149. </template><template>
  1150.   
  1151. </template><template>
  1152.   
  1153. </template><template>
  1154.   
  1155. </template><template>
  1156.   
  1157. </template><template>
  1158.   
  1159. </template>var buffer = await udpClient.ReceiveAsync(token);
  1160. <template>
  1161.   
  1162. </template><template>
  1163.   
  1164. </template><template>
  1165.   
  1166. </template><template>
  1167.   
  1168. </template><template>
  1169.   
  1170. </template><template>
  1171.   
  1172. </template><template>
  1173.   
  1174. </template><template>
  1175.   
  1176. </template><template>
  1177.   
  1178. </template><template>
  1179.   
  1180. </template>await _hubContext.Clients.Client(connectionId).SendAsync("WriteDataAsync", Encoding.UTF8.GetString(buffer.Buffer));
  1181. <template>
  1182.   
  1183. </template><template>
  1184.   
  1185. </template><template>
  1186.   
  1187. </template><template>
  1188.   
  1189. </template><template>
  1190.   
  1191. </template><template>
  1192.   
  1193. </template><template>
  1194.   
  1195. </template><template>
  1196.   
  1197. </template><template>
  1198.   
  1199. </template><template>
  1200.   
  1201. </template>stringBuilder.Clear();
  1202. <template>
  1203.   
  1204. </template><template>
  1205.   
  1206. </template><template>
  1207.   
  1208. </template><template>
  1209.   
  1210. </template><template>
  1211.   
  1212. </template><template>
  1213.   
  1214. </template><template>
  1215.   
  1216. </template><template>
  1217.   
  1218. </template>}
  1219. <template>
  1220.   
  1221. </template><template>
  1222.   
  1223. </template><template>
  1224.   
  1225. </template><template>
  1226.   
  1227. </template><template>
  1228.   
  1229. </template><template>
  1230.   
  1231. </template><template>
  1232.   
  1233. </template><template>
  1234.   
  1235. </template>catch (Exception e)
  1236. <template>
  1237.   
  1238. </template><template>
  1239.   
  1240. </template><template>
  1241.   
  1242. </template><template>
  1243.   
  1244. </template><template>
  1245.   
  1246. </template><template>
  1247.   
  1248. </template><template>
  1249.   
  1250. </template><template>
  1251.   
  1252. </template>{
  1253. <template>
  1254.   
  1255. </template><template>
  1256.   
  1257. </template><template>
  1258.   
  1259. </template><template>
  1260.   
  1261. </template><template>
  1262.   
  1263. </template><template>
  1264.   
  1265. </template><template>
  1266.   
  1267. </template><template>
  1268.   
  1269. </template><template>
  1270.   
  1271. </template><template>
  1272.   
  1273. </template>_logger.LogError(e, "ConnectionId: {ConnectionId} Unable to read data and send message.", connectionId);
  1274. <template>
  1275.   
  1276. </template><template>
  1277.   
  1278. </template><template>
  1279.   
  1280. </template><template>
  1281.   
  1282. </template><template>
  1283.   
  1284. </template><template>
  1285.   
  1286. </template><template>
  1287.   
  1288. </template><template>
  1289.   
  1290. </template><template>
  1291.   
  1292. </template><template>
  1293.   
  1294. </template>break;
  1295. <template>
  1296.   
  1297. </template><template>
  1298.   
  1299. </template><template>
  1300.   
  1301. </template><template>
  1302.   
  1303. </template><template>
  1304.   
  1305. </template><template>
  1306.   
  1307. </template><template>
  1308.   
  1309. </template><template>
  1310.   
  1311. </template>}
  1312. <template>
  1313.   
  1314. </template><template>
  1315.   
  1316. </template><template>
  1317.   
  1318. </template><template>
  1319.   
  1320. </template><template>
  1321.   
  1322. </template><template>
  1323.   
  1324. </template>}
  1325. <template>
  1326.   
  1327. </template><template>
  1328.   
  1329. </template><template>
  1330.   
  1331. </template><template>
  1332.   
  1333. </template><template>
  1334.   
  1335. </template><template>
  1336.   
  1337. </template>// 如果客户端断开连接或者超时 10 分钟,关闭进程
  1338. <template>
  1339.   
  1340. </template><template>
  1341.   
  1342. </template><template>
  1343.   
  1344. </template><template>
  1345.   
  1346. </template><template>
  1347.   
  1348. </template><template>
  1349.   
  1350. </template>if (process?.HasExited ?? false) process?.Kill();
  1351. <template>
  1352.   
  1353. </template><template>
  1354.   
  1355. </template><template>
  1356.   
  1357. </template><template>
  1358.   
  1359. </template><template>
  1360.   
  1361. </template><template>
  1362.   
  1363. </template>if (lastActivity.AddMinutes(10) < DateTime.Now)
  1364. <template>
  1365.   
  1366. </template><template>
  1367.   
  1368. </template><template>
  1369.   
  1370. </template><template>
  1371.   
  1372. </template><template>
  1373.   
  1374. </template><template>
  1375.   
  1376. </template>{
  1377. <template>
  1378.   
  1379. </template><template>
  1380.   
  1381. </template><template>
  1382.   
  1383. </template><template>
  1384.   
  1385. </template><template>
  1386.   
  1387. </template><template>
  1388.   
  1389. </template><template>
  1390.   
  1391. </template><template>
  1392.   
  1393. </template>_logger.LogInformation("ConnectionId: {ConnectionId} Pty session has been closed because of inactivity.", connectionId);
  1394. <template>
  1395.   
  1396. </template><template>
  1397.   
  1398. </template><template>
  1399.   
  1400. </template><template>
  1401.   
  1402. </template><template>
  1403.   
  1404. </template><template>
  1405.   
  1406. </template><template>
  1407.   
  1408. </template><template>
  1409.   
  1410. </template>try
  1411. <template>
  1412.   
  1413. </template><template>
  1414.   
  1415. </template><template>
  1416.   
  1417. </template><template>
  1418.   
  1419. </template><template>
  1420.   
  1421. </template><template>
  1422.   
  1423. </template><template>
  1424.   
  1425. </template><template>
  1426.   
  1427. </template>{
  1428. <template>
  1429.   
  1430. </template><template>
  1431.   
  1432. </template><template>
  1433.   
  1434. </template><template>
  1435.   
  1436. </template><template>
  1437.   
  1438. </template><template>
  1439.   
  1440. </template><template>
  1441.   
  1442. </template><template>
  1443.   
  1444. </template><template>
  1445.   
  1446. </template><template>
  1447.   
  1448. </template>await _hubContext.Clients.Client(connectionId).SendAsync("WriteErrorAsync", "InactiveTimeTooLong");
  1449. <template>
  1450.   
  1451. </template><template>
  1452.   
  1453. </template><template>
  1454.   
  1455. </template><template>
  1456.   
  1457. </template><template>
  1458.   
  1459. </template><template>
  1460.   
  1461. </template><template>
  1462.   
  1463. </template><template>
  1464.   
  1465. </template>}
  1466. <template>
  1467.   
  1468. </template><template>
  1469.   
  1470. </template><template>
  1471.   
  1472. </template><template>
  1473.   
  1474. </template><template>
  1475.   
  1476. </template><template>
  1477.   
  1478. </template><template>
  1479.   
  1480. </template><template>
  1481.   
  1482. </template>catch (Exception e)
  1483. <template>
  1484.   
  1485. </template><template>
  1486.   
  1487. </template><template>
  1488.   
  1489. </template><template>
  1490.   
  1491. </template><template>
  1492.   
  1493. </template><template>
  1494.   
  1495. </template><template>
  1496.   
  1497. </template><template>
  1498.   
  1499. </template>{
  1500. <template>
  1501.   
  1502. </template><template>
  1503.   
  1504. </template><template>
  1505.   
  1506. </template><template>
  1507.   
  1508. </template><template>
  1509.   
  1510. </template><template>
  1511.   
  1512. </template><template>
  1513.   
  1514. </template><template>
  1515.   
  1516. </template><template>
  1517.   
  1518. </template><template>
  1519.   
  1520. </template>_logger.LogError(e, "ConnectionId: {ConnectionId} Unable to send message.", connectionId);
  1521. <template>
  1522.   
  1523. </template><template>
  1524.   
  1525. </template><template>
  1526.   
  1527. </template><template>
  1528.   
  1529. </template><template>
  1530.   
  1531. </template><template>
  1532.   
  1533. </template><template>
  1534.   
  1535. </template><template>
  1536.   
  1537. </template>}
  1538. <template>
  1539.   
  1540. </template><template>
  1541.   
  1542. </template><template>
  1543.   
  1544. </template><template>
  1545.   
  1546. </template><template>
  1547.   
  1548. </template><template>
  1549.   
  1550. </template>}
  1551. <template>
  1552.   
  1553. </template><template>
  1554.   
  1555. </template><template>
  1556.   
  1557. </template><template>
  1558.   
  1559. </template><template>
  1560.   
  1561. </template><template>
  1562.   
  1563. </template>if (token.IsCancellationRequested)
  1564. <template>
  1565.   
  1566. </template><template>
  1567.   
  1568. </template><template>
  1569.   
  1570. </template><template>
  1571.   
  1572. </template><template>
  1573.   
  1574. </template><template>
  1575.   
  1576. </template>{
  1577. <template>
  1578.   
  1579. </template><template>
  1580.   
  1581. </template><template>
  1582.   
  1583. </template><template>
  1584.   
  1585. </template><template>
  1586.   
  1587. </template><template>
  1588.   
  1589. </template><template>
  1590.   
  1591. </template><template>
  1592.   
  1593. </template>_logger.LogInformation("ConnectionId: {ConnectionId} Pty session has been closed because of session closed.", connectionId);
  1594. <template>
  1595.   
  1596. </template><template>
  1597.   
  1598. </template><template>
  1599.   
  1600. </template><template>
  1601.   
  1602. </template><template>
  1603.   
  1604. </template><template>
  1605.   
  1606. </template><template>
  1607.   
  1608. </template><template>
  1609.   
  1610. </template>try
  1611. <template>
  1612.   
  1613. </template><template>
  1614.   
  1615. </template><template>
  1616.   
  1617. </template><template>
  1618.   
  1619. </template><template>
  1620.   
  1621. </template><template>
  1622.   
  1623. </template><template>
  1624.   
  1625. </template><template>
  1626.   
  1627. </template>{
  1628. <template>
  1629.   
  1630. </template><template>
  1631.   
  1632. </template><template>
  1633.   
  1634. </template><template>
  1635.   
  1636. </template><template>
  1637.   
  1638. </template><template>
  1639.   
  1640. </template><template>
  1641.   
  1642. </template><template>
  1643.   
  1644. </template><template>
  1645.   
  1646. </template><template>
  1647.   
  1648. </template>await _hubContext.Clients.Client(connectionId).SendAsync("WriteErrorAsync", "SessionClosed");
  1649. <template>
  1650.   
  1651. </template><template>
  1652.   
  1653. </template><template>
  1654.   
  1655. </template><template>
  1656.   
  1657. </template><template>
  1658.   
  1659. </template><template>
  1660.   
  1661. </template><template>
  1662.   
  1663. </template><template>
  1664.   
  1665. </template>}
  1666. <template>
  1667.   
  1668. </template><template>
  1669.   
  1670. </template><template>
  1671.   
  1672. </template><template>
  1673.   
  1674. </template><template>
  1675.   
  1676. </template><template>
  1677.   
  1678. </template><template>
  1679.   
  1680. </template><template>
  1681.   
  1682. </template>catch (Exception e)
  1683. <template>
  1684.   
  1685. </template><template>
  1686.   
  1687. </template><template>
  1688.   
  1689. </template><template>
  1690.   
  1691. </template><template>
  1692.   
  1693. </template><template>
  1694.   
  1695. </template><template>
  1696.   
  1697. </template><template>
  1698.   
  1699. </template>{
  1700. <template>
  1701.   
  1702. </template><template>
  1703.   
  1704. </template><template>
  1705.   
  1706. </template><template>
  1707.   
  1708. </template><template>
  1709.   
  1710. </template><template>
  1711.   
  1712. </template><template>
  1713.   
  1714. </template><template>
  1715.   
  1716. </template><template>
  1717.   
  1718. </template><template>
  1719.   
  1720. </template>_logger.LogError(e, "ConnectionId: {ConnectionId} Unable to send message.", connectionId);
  1721. <template>
  1722.   
  1723. </template><template>
  1724.   
  1725. </template><template>
  1726.   
  1727. </template><template>
  1728.   
  1729. </template><template>
  1730.   
  1731. </template><template>
  1732.   
  1733. </template><template>
  1734.   
  1735. </template><template>
  1736.   
  1737. </template>}
  1738. <template>
  1739.   
  1740. </template><template>
  1741.   
  1742. </template><template>
  1743.   
  1744. </template><template>
  1745.   
  1746. </template><template>
  1747.   
  1748. </template><template>
  1749.   
  1750. </template>}
  1751. <template>
  1752.   
  1753. </template><template>
  1754.   
  1755. </template><template>
  1756.   
  1757. </template><template>
  1758.   
  1759. </template><template>
  1760.   
  1761. </template><template>
  1762.   
  1763. </template>Dispose();
  1764. <template>
  1765.   
  1766. </template><template>
  1767.   
  1768. </template><template>
  1769.   
  1770. </template><template>
  1771.   
  1772. </template>}
  1773. <template>
  1774.   
  1775. </template><template>
  1776.   
  1777. </template><template>
  1778.   
  1779. </template><template>
  1780.   
  1781. </template>/// <summary>
  1782. <template>
  1783.   
  1784. </template><template>
  1785.   
  1786. </template><template>
  1787.   
  1788. </template><template>
  1789.   
  1790. </template>/// 接收 SignalR 数据,并发送到客户端
  1791. <template>
  1792.   
  1793. </template><template>
  1794.   
  1795. </template><template>
  1796.   
  1797. </template><template>
  1798.   
  1799. </template>/// </summary>
  1800. <template>
  1801.   
  1802. </template><template>
  1803.   
  1804. </template><template>
  1805.   
  1806. </template><template>
  1807.   
  1808. </template>/// <param name="data">数据</param>
  1809. <template>
  1810.   
  1811. </template><template>
  1812.   
  1813. </template><template>
  1814.   
  1815. </template><template>
  1816.   
  1817. </template>/// <returns></returns>
  1818. <template>
  1819.   
  1820. </template><template>
  1821.   
  1822. </template><template>
  1823.   
  1824. </template><template>
  1825.   
  1826. </template>/// <exception cref="AppException"></exception>
  1827. <template>
  1828.   
  1829. </template><template>
  1830.   
  1831. </template><template>
  1832.   
  1833. </template><template>
  1834.   
  1835. </template>public async Task WriteDataAsync(string data)
  1836. <template>
  1837.   
  1838. </template><template>
  1839.   
  1840. </template><template>
  1841.   
  1842. </template><template>
  1843.   
  1844. </template>{
  1845. <template>
  1846.   
  1847. </template><template>
  1848.   
  1849. </template><template>
  1850.   
  1851. </template><template>
  1852.   
  1853. </template><template>
  1854.   
  1855. </template><template>
  1856.   
  1857. </template>if (disposedValue)
  1858. <template>
  1859.   
  1860. </template><template>
  1861.   
  1862. </template><template>
  1863.   
  1864. </template><template>
  1865.   
  1866. </template><template>
  1867.   
  1868. </template><template>
  1869.   
  1870. </template>{
  1871. <template>
  1872.   
  1873. </template><template>
  1874.   
  1875. </template><template>
  1876.   
  1877. </template><template>
  1878.   
  1879. </template><template>
  1880.   
  1881. </template><template>
  1882.   
  1883. </template><template>
  1884.   
  1885. </template><template>
  1886.   
  1887. </template>throw new AppException("SessionClosed");
  1888. <template>
  1889.   
  1890. </template><template>
  1891.   
  1892. </template><template>
  1893.   
  1894. </template><template>
  1895.   
  1896. </template><template>
  1897.   
  1898. </template><template>
  1899.   
  1900. </template>}
  1901. <template>
  1902.   
  1903. </template><template>
  1904.   
  1905. </template><template>
  1906.   
  1907. </template><template>
  1908.   
  1909. </template><template>
  1910.   
  1911. </template><template>
  1912.   
  1913. </template>try
  1914. <template>
  1915.   
  1916. </template><template>
  1917.   
  1918. </template><template>
  1919.   
  1920. </template><template>
  1921.   
  1922. </template><template>
  1923.   
  1924. </template><template>
  1925.   
  1926. </template>{
  1927. <template>
  1928.   
  1929. </template><template>
  1930.   
  1931. </template><template>
  1932.   
  1933. </template><template>
  1934.   
  1935. </template><template>
  1936.   
  1937. </template><template>
  1938.   
  1939. </template><template>
  1940.   
  1941. </template><template>
  1942.   
  1943. </template>lastActivity = DateTime.Now;
  1944. <template>
  1945.   
  1946. </template><template>
  1947.   
  1948. </template><template>
  1949.   
  1950. </template><template>
  1951.   
  1952. </template><template>
  1953.   
  1954. </template><template>
  1955.   
  1956. </template><template>
  1957.   
  1958. </template><template>
  1959.   
  1960. </template>await udpClient.SendAsync(Encoding.UTF8.GetBytes(data));
  1961. <template>
  1962.   
  1963. </template><template>
  1964.   
  1965. </template><template>
  1966.   
  1967. </template><template>
  1968.   
  1969. </template><template>
  1970.   
  1971. </template><template>
  1972.   
  1973. </template>}
  1974. <template>
  1975.   
  1976. </template><template>
  1977.   
  1978. </template><template>
  1979.   
  1980. </template><template>
  1981.   
  1982. </template><template>
  1983.   
  1984. </template><template>
  1985.   
  1986. </template>catch (Exception e)
  1987. <template>
  1988.   
  1989. </template><template>
  1990.   
  1991. </template><template>
  1992.   
  1993. </template><template>
  1994.   
  1995. </template><template>
  1996.   
  1997. </template><template>
  1998.   
  1999. </template>{
  2000. <template>
  2001.   
  2002. </template><template>
  2003.   
  2004. </template><template>
  2005.   
  2006. </template><template>
  2007.   
  2008. </template><template>
  2009.   
  2010. </template><template>
  2011.   
  2012. </template><template>
  2013.   
  2014. </template><template>
  2015.   
  2016. </template>CancellationTokenSource.Cancel();
  2017. <template>
  2018.   
  2019. </template><template>
  2020.   
  2021. </template><template>
  2022.   
  2023. </template><template>
  2024.   
  2025. </template><template>
  2026.   
  2027. </template><template>
  2028.   
  2029. </template><template>
  2030.   
  2031. </template><template>
  2032.   
  2033. </template>Dispose();
  2034. <template>
  2035.   
  2036. </template><template>
  2037.   
  2038. </template><template>
  2039.   
  2040. </template><template>
  2041.   
  2042. </template><template>
  2043.   
  2044. </template><template>
  2045.   
  2046. </template><template>
  2047.   
  2048. </template><template>
  2049.   
  2050. </template>throw new AppException("SessionClosed", e);
  2051. <template>
  2052.   
  2053. </template><template>
  2054.   
  2055. </template><template>
  2056.   
  2057. </template><template>
  2058.   
  2059. </template><template>
  2060.   
  2061. </template><template>
  2062.   
  2063. </template>}
  2064. <template>
  2065.   
  2066. </template><template>
  2067.   
  2068. </template><template>
  2069.   
  2070. </template><template>
  2071.   
  2072. </template>}
  2073. <template>
  2074.   
  2075. </template><template>
  2076.   
  2077. </template><template>
  2078.   
  2079. </template><template>
  2080.   
  2081. </template>/// <summary>
  2082. <template>
  2083.   
  2084. </template><template>
  2085.   
  2086. </template><template>
  2087.   
  2088. </template><template>
  2089.   
  2090. </template>/// 回收资源
  2091. <template>
  2092.   
  2093. </template><template>
  2094.   
  2095. </template><template>
  2096.   
  2097. </template><template>
  2098.   
  2099. </template>/// </summary>
  2100. <template>
  2101.   
  2102. </template><template>
  2103.   
  2104. </template><template>
  2105.   
  2106. </template><template>
  2107.   
  2108. </template>/// <param name="disposing"></param>
  2109. <template>
  2110.   
  2111. </template><template>
  2112.   
  2113. </template><template>
  2114.   
  2115. </template><template>
  2116.   
  2117. </template>protected virtual void Dispose(bool disposing)
  2118. <template>
  2119.   
  2120. </template><template>
  2121.   
  2122. </template><template>
  2123.   
  2124. </template><template>
  2125.   
  2126. </template>{
  2127. <template>
  2128.   
  2129. </template><template>
  2130.   
  2131. </template><template>
  2132.   
  2133. </template><template>
  2134.   
  2135. </template><template>
  2136.   
  2137. </template><template>
  2138.   
  2139. </template>if (!disposedValue)
  2140. <template>
  2141.   
  2142. </template><template>
  2143.   
  2144. </template><template>
  2145.   
  2146. </template><template>
  2147.   
  2148. </template><template>
  2149.   
  2150. </template><template>
  2151.   
  2152. </template>{
  2153. <template>
  2154.   
  2155. </template><template>
  2156.   
  2157. </template><template>
  2158.   
  2159. </template><template>
  2160.   
  2161. </template><template>
  2162.   
  2163. </template><template>
  2164.   
  2165. </template><template>
  2166.   
  2167. </template><template>
  2168.   
  2169. </template>if (disposing)
  2170. <template>
  2171.   
  2172. </template><template>
  2173.   
  2174. </template><template>
  2175.   
  2176. </template><template>
  2177.   
  2178. </template><template>
  2179.   
  2180. </template><template>
  2181.   
  2182. </template><template>
  2183.   
  2184. </template><template>
  2185.   
  2186. </template>{
  2187. <template>
  2188.   
  2189. </template><template>
  2190.   
  2191. </template><template>
  2192.   
  2193. </template><template>
  2194.   
  2195. </template><template>
  2196.   
  2197. </template><template>
  2198.   
  2199. </template><template>
  2200.   
  2201. </template><template>
  2202.   
  2203. </template><template>
  2204.   
  2205. </template><template>
  2206.   
  2207. </template>CancellationTokenSource.Cancel();
  2208. <template>
  2209.   
  2210. </template><template>
  2211.   
  2212. </template><template>
  2213.   
  2214. </template><template>
  2215.   
  2216. </template><template>
  2217.   
  2218. </template><template>
  2219.   
  2220. </template><template>
  2221.   
  2222. </template><template>
  2223.   
  2224. </template><template>
  2225.   
  2226. </template><template>
  2227.   
  2228. </template>udpClient.Dispose();
  2229. <template>
  2230.   
  2231. </template><template>
  2232.   
  2233. </template><template>
  2234.   
  2235. </template><template>
  2236.   
  2237. </template><template>
  2238.   
  2239. </template><template>
  2240.   
  2241. </template><template>
  2242.   
  2243. </template><template>
  2244.   
  2245. </template>}
  2246. <template>
  2247.   
  2248. </template><template>
  2249.   
  2250. </template><template>
  2251.   
  2252. </template><template>
  2253.   
  2254. </template><template>
  2255.   
  2256. </template><template>
  2257.   
  2258. </template><template>
  2259.   
  2260. </template><template>
  2261.   
  2262. </template>disposedValue = true;
  2263. <template>
  2264.   
  2265. </template><template>
  2266.   
  2267. </template><template>
  2268.   
  2269. </template><template>
  2270.   
  2271. </template><template>
  2272.   
  2273. </template><template>
  2274.   
  2275. </template><template>
  2276.   
  2277. </template><template>
  2278.   
  2279. </template>Closed(this, new EventArgs());
  2280. <template>
  2281.   
  2282. </template><template>
  2283.   
  2284. </template><template>
  2285.   
  2286. </template><template>
  2287.   
  2288. </template><template>
  2289.   
  2290. </template><template>
  2291.   
  2292. </template>}
  2293. <template>
  2294.   
  2295. </template><template>
  2296.   
  2297. </template><template>
  2298.   
  2299. </template><template>
  2300.   
  2301. </template>}
  2302. <template>
  2303.   
  2304. </template><template>
  2305.   
  2306. </template><template>
  2307.   
  2308. </template><template>
  2309.   
  2310. </template>public void Dispose()
  2311. <template>
  2312.   
  2313. </template><template>
  2314.   
  2315. </template><template>
  2316.   
  2317. </template><template>
  2318.   
  2319. </template>{
  2320. <template>
  2321.   
  2322. </template><template>
  2323.   
  2324. </template><template>
  2325.   
  2326. </template><template>
  2327.   
  2328. </template><template>
  2329.   
  2330. </template><template>
  2331.   
  2332. </template>Dispose(disposing: true);
  2333. <template>
  2334.   
  2335. </template><template>
  2336.   
  2337. </template><template>
  2338.   
  2339. </template><template>
  2340.   
  2341. </template><template>
  2342.   
  2343. </template><template>
  2344.   
  2345. </template>GC.SuppressFinalize(this);
  2346. <template>
  2347.   
  2348. </template><template>
  2349.   
  2350. </template><template>
  2351.   
  2352. </template><template>
  2353.   
  2354. </template>}
  2355. <template>
  2356.   
  2357. </template><template>
  2358.   
  2359. </template>}
复制代码

  • SshService 这段代码用于管理 SshPtyConnection 和 SignalR 客户端连接之间的关系
  1. <template>
  2.   
  3. </template><template>
  4.   
  5. </template>public class SshService : IDisposable
  6. <template>
  7.   
  8. </template><template>
  9.   
  10. </template>{
  11. <template>
  12.   
  13. </template><template>
  14.   
  15. </template><template>
  16.   
  17. </template><template>
  18.   
  19. </template>private bool disposedValue;
  20. <template>
  21.   
  22. </template><template>
  23.   
  24. </template><template>
  25.   
  26. </template><template>
  27.   
  28. </template>private readonly IHubContext<SshHub> _hubContext;
  29. <template>
  30.   
  31. </template><template>
  32.   
  33. </template><template>
  34.   
  35. </template><template>
  36.   
  37. </template>private readonly ILoggerFactory _loggerFactory;
  38. <template>
  39.   
  40. </template><template>
  41.   
  42. </template><template>
  43.   
  44. </template><template>
  45.   
  46. </template>private Dictionary<string, SshPtyConnection> _connections;
  47. <template>
  48.   
  49. </template><template>
  50.   
  51. </template><template>
  52.   
  53. </template><template>
  54.   
  55. </template>public SshService(IHubContext<SshHub> hubContext, ILoggerFactory loggerFactory)
  56. <template>
  57.   
  58. </template><template>
  59.   
  60. </template><template>
  61.   
  62. </template><template>
  63.   
  64. </template>{
  65. <template>
  66.   
  67. </template><template>
  68.   
  69. </template><template>
  70.   
  71. </template><template>
  72.   
  73. </template><template>
  74.   
  75. </template><template>
  76.   
  77. </template>_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
  78. <template>
  79.   
  80. </template><template>
  81.   
  82. </template><template>
  83.   
  84. </template><template>
  85.   
  86. </template><template>
  87.   
  88. </template><template>
  89.   
  90. </template>_connections = new Dictionary<string, SshPtyConnection>();
  91. <template>
  92.   
  93. </template><template>
  94.   
  95. </template><template>
  96.   
  97. </template><template>
  98.   
  99. </template><template>
  100.   
  101. </template><template>
  102.   
  103. </template>_loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
  104. <template>
  105.   
  106. </template><template>
  107.   
  108. </template><template>
  109.   
  110. </template><template>
  111.   
  112. </template>}
  113. <template>
  114.   
  115. </template><template>
  116.   
  117. </template><template>
  118.   
  119. </template><template>
  120.   
  121. </template>/// <summary>
  122. <template>
  123.   
  124. </template><template>
  125.   
  126. </template><template>
  127.   
  128. </template><template>
  129.   
  130. </template>/// 创建终端连接
  131. <template>
  132.   
  133. </template><template>
  134.   
  135. </template><template>
  136.   
  137. </template><template>
  138.   
  139. </template>/// </summary>
  140. <template>
  141.   
  142. </template><template>
  143.   
  144. </template><template>
  145.   
  146. </template><template>
  147.   
  148. </template>/// <param name="connectionId">连接 ID</param>
  149. <template>
  150.   
  151. </template><template>
  152.   
  153. </template><template>
  154.   
  155. </template><template>
  156.   
  157. </template>/// <param name="username">用户名</param>
  158. <template>
  159.   
  160. </template><template>
  161.   
  162. </template><template>
  163.   
  164. </template><template>
  165.   
  166. </template>/// <param name="height">行数</param>
  167. <template>
  168.   
  169. </template><template>
  170.   
  171. </template><template>
  172.   
  173. </template><template>
  174.   
  175. </template>/// <param name="width">列数</param>
  176. <template>
  177.   
  178. </template><template>
  179.   
  180. </template><template>
  181.   
  182. </template><template>
  183.   
  184. </template>/// <returns></returns>
  185. <template>
  186.   
  187. </template><template>
  188.   
  189. </template><template>
  190.   
  191. </template><template>
  192.   
  193. </template>/// <exception cref="InvalidOperationException"></exception>
  194. <template>
  195.   
  196. </template><template>
  197.   
  198. </template><template>
  199.   
  200. </template><template>
  201.   
  202. </template>public Task CreateConnectionAsync(string connectionId, string username, int height, int width)
  203. <template>
  204.   
  205. </template><template>
  206.   
  207. </template><template>
  208.   
  209. </template><template>
  210.   
  211. </template>{
  212. <template>
  213.   
  214. </template><template>
  215.   
  216. </template><template>
  217.   
  218. </template><template>
  219.   
  220. </template><template>
  221.   
  222. </template><template>
  223.   
  224. </template>if (_connections.ContainsKey(connectionId))
  225. <template>
  226.   
  227. </template><template>
  228.   
  229. </template><template>
  230.   
  231. </template><template>
  232.   
  233. </template><template>
  234.   
  235. </template><template>
  236.   
  237. </template><template>
  238.   
  239. </template><template>
  240.   
  241. </template>throw new InvalidOperationException();
  242. <template>
  243.   
  244. </template><template>
  245.   
  246. </template><template>
  247.   
  248. </template><template>
  249.   
  250. </template><template>
  251.   
  252. </template><template>
  253.   
  254. </template>var connection = new SshPtyConnection(_hubContext, _loggerFactory.CreateLogger<SshPtyConnection>());
  255. <template>
  256.   
  257. </template><template>
  258.   
  259. </template><template>
  260.   
  261. </template><template>
  262.   
  263. </template><template>
  264.   
  265. </template><template>
  266.   
  267. </template>connection.Closed += (sender, args) =>
  268. <template>
  269.   
  270. </template><template>
  271.   
  272. </template><template>
  273.   
  274. </template><template>
  275.   
  276. </template><template>
  277.   
  278. </template><template>
  279.   
  280. </template>{
  281. <template>
  282.   
  283. </template><template>
  284.   
  285. </template><template>
  286.   
  287. </template><template>
  288.   
  289. </template><template>
  290.   
  291. </template><template>
  292.   
  293. </template><template>
  294.   
  295. </template><template>
  296.   
  297. </template>_hubContext.Clients.Client(connectionId).SendAsync("WriteErrorAsync", "SessionClosed");
  298. <template>
  299.   
  300. </template><template>
  301.   
  302. </template><template>
  303.   
  304. </template><template>
  305.   
  306. </template><template>
  307.   
  308. </template><template>
  309.   
  310. </template><template>
  311.   
  312. </template><template>
  313.   
  314. </template>_connections.Remove(connectionId);
  315. <template>
  316.   
  317. </template><template>
  318.   
  319. </template><template>
  320.   
  321. </template><template>
  322.   
  323. </template><template>
  324.   
  325. </template><template>
  326.   
  327. </template>};
  328. <template>
  329.   
  330. </template><template>
  331.   
  332. </template><template>
  333.   
  334. </template><template>
  335.   
  336. </template><template>
  337.   
  338. </template><template>
  339.   
  340. </template>_connections.Add(connectionId, connection);
  341. <template>
  342.   
  343. </template><template>
  344.   
  345. </template><template>
  346.   
  347. </template><template>
  348.   
  349. </template><template>
  350.   
  351. </template><template>
  352.   
  353. </template>// 运行一个后台线程
  354. <template>
  355.   
  356. </template><template>
  357.   
  358. </template><template>
  359.   
  360. </template><template>
  361.   
  362. </template><template>
  363.   
  364. </template><template>
  365.   
  366. </template>connection.StartAsync(connectionId, username, height, width);
  367. <template>
  368.   
  369. </template><template>
  370.   
  371. </template><template>
  372.   
  373. </template><template>
  374.   
  375. </template><template>
  376.   
  377. </template><template>
  378.   
  379. </template>return Task.CompletedTask;
  380. <template>
  381.   
  382. </template><template>
  383.   
  384. </template><template>
  385.   
  386. </template><template>
  387.   
  388. </template>}
  389. <template>
  390.   
  391. </template><template>
  392.   
  393. </template><template>
  394.   
  395. </template><template>
  396.   
  397. </template>/// <summary>
  398. <template>
  399.   
  400. </template><template>
  401.   
  402. </template><template>
  403.   
  404. </template><template>
  405.   
  406. </template>/// 写入数据
  407. <template>
  408.   
  409. </template><template>
  410.   
  411. </template><template>
  412.   
  413. </template><template>
  414.   
  415. </template>/// </summary>
  416. <template>
  417.   
  418. </template><template>
  419.   
  420. </template><template>
  421.   
  422. </template><template>
  423.   
  424. </template>/// <param name="connectionId">连接 ID</param>
  425. <template>
  426.   
  427. </template><template>
  428.   
  429. </template><template>
  430.   
  431. </template><template>
  432.   
  433. </template>/// <param name="data">数据</param>
  434. <template>
  435.   
  436. </template><template>
  437.   
  438. </template><template>
  439.   
  440. </template><template>
  441.   
  442. </template>/// <exception cref="AppException"></exception>
  443. <template>
  444.   
  445. </template><template>
  446.   
  447. </template><template>
  448.   
  449. </template><template>
  450.   
  451. </template>public async Task ReadDataAsync(string connectionId, string data)
  452. <template>
  453.   
  454. </template><template>
  455.   
  456. </template><template>
  457.   
  458. </template><template>
  459.   
  460. </template>{
  461. <template>
  462.   
  463. </template><template>
  464.   
  465. </template><template>
  466.   
  467. </template><template>
  468.   
  469. </template><template>
  470.   
  471. </template><template>
  472.   
  473. </template>if (_connections.TryGetValue(connectionId, out var connection))
  474. <template>
  475.   
  476. </template><template>
  477.   
  478. </template><template>
  479.   
  480. </template><template>
  481.   
  482. </template><template>
  483.   
  484. </template><template>
  485.   
  486. </template>{
  487. <template>
  488.   
  489. </template><template>
  490.   
  491. </template><template>
  492.   
  493. </template><template>
  494.   
  495. </template><template>
  496.   
  497. </template><template>
  498.   
  499. </template><template>
  500.   
  501. </template><template>
  502.   
  503. </template>await connection.WriteDataAsync(data);
  504. <template>
  505.   
  506. </template><template>
  507.   
  508. </template><template>
  509.   
  510. </template><template>
  511.   
  512. </template><template>
  513.   
  514. </template><template>
  515.   
  516. </template>}
  517. <template>
  518.   
  519. </template><template>
  520.   
  521. </template><template>
  522.   
  523. </template><template>
  524.   
  525. </template><template>
  526.   
  527. </template><template>
  528.   
  529. </template>else
  530. <template>
  531.   
  532. </template><template>
  533.   
  534. </template><template>
  535.   
  536. </template><template>
  537.   
  538. </template><template>
  539.   
  540. </template><template>
  541.   
  542. </template><template>
  543.   
  544. </template><template>
  545.   
  546. </template>throw new AppException("SessionClosed");
  547. <template>
  548.   
  549. </template><template>
  550.   
  551. </template><template>
  552.   
  553. </template><template>
  554.   
  555. </template>}
  556. <template>
  557.   
  558. </template><template>
  559.   
  560. </template><template>
  561.   
  562. </template><template>
  563.   
  564. </template>/// <summary>
  565. <template>
  566.   
  567. </template><template>
  568.   
  569. </template><template>
  570.   
  571. </template><template>
  572.   
  573. </template>/// 关闭连接
  574. <template>
  575.   
  576. </template><template>
  577.   
  578. </template><template>
  579.   
  580. </template><template>
  581.   
  582. </template>/// </summary>
  583. <template>
  584.   
  585. </template><template>
  586.   
  587. </template><template>
  588.   
  589. </template><template>
  590.   
  591. </template>/// <param name="connectionId">连接 ID</param>
  592. <template>
  593.   
  594. </template><template>
  595.   
  596. </template><template>
  597.   
  598. </template><template>
  599.   
  600. </template>/// <exception cref="AppException"></exception>
  601. <template>
  602.   
  603. </template><template>
  604.   
  605. </template><template>
  606.   
  607. </template><template>
  608.   
  609. </template>public Task CloseConnectionAsync(string connectionId)
  610. <template>
  611.   
  612. </template><template>
  613.   
  614. </template><template>
  615.   
  616. </template><template>
  617.   
  618. </template>{
  619. <template>
  620.   
  621. </template><template>
  622.   
  623. </template><template>
  624.   
  625. </template><template>
  626.   
  627. </template><template>
  628.   
  629. </template><template>
  630.   
  631. </template>if (_connections.TryGetValue(connectionId, out var connection))
  632. <template>
  633.   
  634. </template><template>
  635.   
  636. </template><template>
  637.   
  638. </template><template>
  639.   
  640. </template><template>
  641.   
  642. </template><template>
  643.   
  644. </template>{
  645. <template>
  646.   
  647. </template><template>
  648.   
  649. </template><template>
  650.   
  651. </template><template>
  652.   
  653. </template><template>
  654.   
  655. </template><template>
  656.   
  657. </template><template>
  658.   
  659. </template><template>
  660.   
  661. </template>connection.Dispose();
  662. <template>
  663.   
  664. </template><template>
  665.   
  666. </template><template>
  667.   
  668. </template><template>
  669.   
  670. </template><template>
  671.   
  672. </template><template>
  673.   
  674. </template>}
  675. <template>
  676.   
  677. </template><template>
  678.   
  679. </template><template>
  680.   
  681. </template><template>
  682.   
  683. </template><template>
  684.   
  685. </template><template>
  686.   
  687. </template>else
  688. <template>
  689.   
  690. </template><template>
  691.   
  692. </template><template>
  693.   
  694. </template><template>
  695.   
  696. </template><template>
  697.   
  698. </template><template>
  699.   
  700. </template><template>
  701.   
  702. </template><template>
  703.   
  704. </template>throw new AppException("SessionClosed");
  705. <template>
  706.   
  707. </template><template>
  708.   
  709. </template><template>
  710.   
  711. </template><template>
  712.   
  713. </template><template>
  714.   
  715. </template><template>
  716.   
  717. </template>return Task.CompletedTask;
  718. <template>
  719.   
  720. </template><template>
  721.   
  722. </template><template>
  723.   
  724. </template><template>
  725.   
  726. </template>}
  727. <template>
  728.   
  729. </template><template>
  730.   
  731. </template><template>
  732.   
  733. </template><template>
  734.   
  735. </template>/// <summary>
  736. <template>
  737.   
  738. </template><template>
  739.   
  740. </template><template>
  741.   
  742. </template><template>
  743.   
  744. </template>/// 回收资源
  745. <template>
  746.   
  747. </template><template>
  748.   
  749. </template><template>
  750.   
  751. </template><template>
  752.   
  753. </template>/// </summary>
  754. <template>
  755.   
  756. </template><template>
  757.   
  758. </template><template>
  759.   
  760. </template><template>
  761.   
  762. </template>/// <param name="disposing"></param>
  763. <template>
  764.   
  765. </template><template>
  766.   
  767. </template><template>
  768.   
  769. </template><template>
  770.   
  771. </template>protected virtual void Dispose(bool disposing)
  772. <template>
  773.   
  774. </template><template>
  775.   
  776. </template><template>
  777.   
  778. </template><template>
  779.   
  780. </template>{
  781. <template>
  782.   
  783. </template><template>
  784.   
  785. </template><template>
  786.   
  787. </template><template>
  788.   
  789. </template><template>
  790.   
  791. </template><template>
  792.   
  793. </template>if (!disposedValue)
  794. <template>
  795.   
  796. </template><template>
  797.   
  798. </template><template>
  799.   
  800. </template><template>
  801.   
  802. </template><template>
  803.   
  804. </template><template>
  805.   
  806. </template>{
  807. <template>
  808.   
  809. </template><template>
  810.   
  811. </template><template>
  812.   
  813. </template><template>
  814.   
  815. </template><template>
  816.   
  817. </template><template>
  818.   
  819. </template><template>
  820.   
  821. </template><template>
  822.   
  823. </template>if (disposing)
  824. <template>
  825.   
  826. </template><template>
  827.   
  828. </template><template>
  829.   
  830. </template><template>
  831.   
  832. </template><template>
  833.   
  834. </template><template>
  835.   
  836. </template><template>
  837.   
  838. </template><template>
  839.   
  840. </template>{
  841. <template>
  842.   
  843. </template><template>
  844.   
  845. </template><template>
  846.   
  847. </template><template>
  848.   
  849. </template><template>
  850.   
  851. </template><template>
  852.   
  853. </template><template>
  854.   
  855. </template><template>
  856.   
  857. </template><template>
  858.   
  859. </template><template>
  860.   
  861. </template>foreach (var item in _connections.Values)
  862. <template>
  863.   
  864. </template><template>
  865.   
  866. </template><template>
  867.   
  868. </template><template>
  869.   
  870. </template><template>
  871.   
  872. </template><template>
  873.   
  874. </template><template>
  875.   
  876. </template><template>
  877.   
  878. </template><template>
  879.   
  880. </template><template>
  881.   
  882. </template>{
  883. <template>
  884.   
  885. </template><template>
  886.   
  887. </template><template>
  888.   
  889. </template><template>
  890.   
  891. </template><template>
  892.   
  893. </template><template>
  894.   
  895. </template><template>
  896.   
  897. </template><template>
  898.   
  899. </template><template>
  900.   
  901. </template><template>
  902.   
  903. </template><template>
  904.   
  905. </template><template>
  906.   
  907. </template>item.Dispose();
  908. <template>
  909.   
  910. </template><template>
  911.   
  912. </template><template>
  913.   
  914. </template><template>
  915.   
  916. </template><template>
  917.   
  918. </template><template>
  919.   
  920. </template><template>
  921.   
  922. </template><template>
  923.   
  924. </template><template>
  925.   
  926. </template><template>
  927.   
  928. </template>}
  929. <template>
  930.   
  931. </template><template>
  932.   
  933. </template><template>
  934.   
  935. </template><template>
  936.   
  937. </template><template>
  938.   
  939. </template><template>
  940.   
  941. </template><template>
  942.   
  943. </template><template>
  944.   
  945. </template>}
  946. <template>
  947.   
  948. </template><template>
  949.   
  950. </template><template>
  951.   
  952. </template><template>
  953.   
  954. </template><template>
  955.   
  956. </template><template>
  957.   
  958. </template><template>
  959.   
  960. </template><template>
  961.   
  962. </template>disposedValue = true;
  963. <template>
  964.   
  965. </template><template>
  966.   
  967. </template><template>
  968.   
  969. </template><template>
  970.   
  971. </template><template>
  972.   
  973. </template><template>
  974.   
  975. </template>}
  976. <template>
  977.   
  978. </template><template>
  979.   
  980. </template><template>
  981.   
  982. </template><template>
  983.   
  984. </template>}
  985. <template>
  986.   
  987. </template><template>
  988.   
  989. </template><template>
  990.   
  991. </template><template>
  992.   
  993. </template>public void Dispose()
  994. <template>
  995.   
  996. </template><template>
  997.   
  998. </template><template>
  999.   
  1000. </template><template>
  1001.   
  1002. </template>{
  1003. <template>
  1004.   
  1005. </template><template>
  1006.   
  1007. </template><template>
  1008.   
  1009. </template><template>
  1010.   
  1011. </template><template>
  1012.   
  1013. </template><template>
  1014.   
  1015. </template>Dispose(disposing: true);
  1016. <template>
  1017.   
  1018. </template><template>
  1019.   
  1020. </template><template>
  1021.   
  1022. </template><template>
  1023.   
  1024. </template><template>
  1025.   
  1026. </template><template>
  1027.   
  1028. </template>GC.SuppressFinalize(this);
  1029. <template>
  1030.   
  1031. </template><template>
  1032.   
  1033. </template><template>
  1034.   
  1035. </template><template>
  1036.   
  1037. </template>}
  1038. <template>
  1039.   
  1040. </template><template>
  1041.   
  1042. </template>}
复制代码

  • WebSsh.vue 这段代码是使用 vue 展示终端窗口的代码
  1. <template>
  2.   
  3. </template>
复制代码

  • SshHub.cs 这个文件是 SignalR 的 Hub 文件,用来做监听的。
  1. <template>
  2.   
  3. </template><template>
  4.   
  5. </template>[Authorize]<template>
  6.   
  7. </template><template>
  8.   
  9. </template>public class SshHub : Hub<template>
  10.   
  11. </template><template>
  12.   
  13. </template>{<template>
  14.   
  15. </template><template>
  16.   
  17. </template><template>
  18.   
  19. </template><template>
  20.   
  21. </template>private readonly SshService _sshService;<template>
  22.   
  23. </template><template>
  24.   
  25. </template><template>
  26.   
  27. </template><template>
  28.   
  29. </template>private readonly ILogger _logger;<template>
  30.   
  31. </template><template>
  32.   
  33. </template><template>
  34.   
  35. </template><template>
  36.   
  37. </template>public SshHub(SshService sshService, ILogger logger)<template>
  38.   
  39. </template><template>
  40.   
  41. </template><template>
  42.   
  43. </template><template>
  44.   
  45. </template>{<template>
  46.   
  47. </template><template>
  48.   
  49. </template><template>
  50.   
  51. </template><template>
  52.   
  53. </template><template>
  54.   
  55. </template><template>
  56.   
  57. </template>_sshService = sshService ?? throw new ArgumentNullException(nameof(sshService));<template>
  58.   
  59. </template><template>
  60.   
  61. </template><template>
  62.   
  63. </template><template>
  64.   
  65. </template><template>
  66.   
  67. </template><template>
  68.   
  69. </template>_logger = logger ?? throw new ArgumentNullException(nameof(logger));<template>
  70.   
  71. </template><template>
  72.   
  73. </template><template>
  74.   
  75. </template><template>
  76.   
  77. </template>}<template>
  78.   
  79. </template><template>
  80.   
  81. </template><template>
  82.   
  83. </template><template>
  84.   
  85. </template>///<template>
  86.   
  87. </template><template>
  88.   
  89. </template><template>
  90.   
  91. </template><template>
  92.   
  93. </template> /// 创建一个新的终端<template>
  94.   
  95. </template><template>
  96.   
  97. </template><template>
  98.   
  99. </template><template>
  100.   
  101. </template>///<template>
  102.   
  103. </template><template>
  104.   
  105. </template><template>
  106.   
  107. </template><template>
  108.   
  109. </template> ///<template>
  110.   
  111. </template><template>
  112.   
  113. </template><template>
  114.   
  115. </template><template>
  116.   
  117. </template> ///<template>
  118.   
  119. </template><template>
  120.   
  121. </template><template>
  122.   
  123. </template><template>
  124.   
  125. </template> ///<template>
  126.   
  127. </template><template>
  128.   
  129. </template><template>
  130.   
  131. </template><template>
  132.   
  133. </template> public async Task CreateNewTerminalAsync(int height = 24, int width = 80)<template>
  134.   
  135. </template><template>
  136.   
  137. </template><template>
  138.   
  139. </template><template>
  140.   
  141. </template>{<template>
  142.   
  143. </template><template>
  144.   
  145. </template><template>
  146.   
  147. </template><template>
  148.   
  149. </template><template>
  150.   
  151. </template><template>
  152.   
  153. </template>try<template>
  154.   
  155. </template><template>
  156.   
  157. </template><template>
  158.   
  159. </template><template>
  160.   
  161. </template><template>
  162.   
  163. </template><template>
  164.   
  165. </template>{<template>
  166.   
  167. </template><template>
  168.   
  169. </template><template>
  170.   
  171. </template><template>
  172.   
  173. </template><template>
  174.   
  175. </template><template>
  176.   
  177. </template><template>
  178.   
  179. </template><template>
  180.   
  181. </template>var username = Context.User?.FindFirst("preferred_username")?.Value;<template>
  182.   
  183. </template><template>
  184.   
  185. </template><template>
  186.   
  187. </template><template>
  188.   
  189. </template><template>
  190.   
  191. </template><template>
  192.   
  193. </template><template>
  194.   
  195. </template><template>
  196.   
  197. </template>if (username == null)<template>
  198.   
  199. </template><template>
  200.   
  201. </template><template>
  202.   
  203. </template><template>
  204.   
  205. </template><template>
  206.   
  207. </template><template>
  208.   
  209. </template><template>
  210.   
  211. </template><template>
  212.   
  213. </template>{<template>
  214.   
  215. </template><template>
  216.   
  217. </template><template>
  218.   
  219. </template><template>
  220.   
  221. </template><template>
  222.   
  223. </template><template>
  224.   
  225. </template><template>
  226.   
  227. </template><template>
  228.   
  229. </template><template>
  230.   
  231. </template><template>
  232.   
  233. </template>return new BaseResponse<template>
  234.   
  235. </template><template>
  236.   
  237. </template><template>
  238.   
  239. </template><template>
  240.   
  241. </template><template>
  242.   
  243. </template><template>
  244.   
  245. </template><template>
  246.   
  247. </template><template>
  248.   
  249. </template><template>
  250.   
  251. </template><template>
  252.   
  253. </template>{<template>
  254.   
  255. </template><template>
  256.   
  257. </template><template>
  258.   
  259. </template><template>
  260.   
  261. </template><template>
  262.   
  263. </template><template>
  264.   
  265. </template><template>
  266.   
  267. </template><template>
  268.   
  269. </template><template>
  270.   
  271. </template><template>
  272.   
  273. </template><template>
  274.   
  275. </template><template>
  276.   
  277. </template>Code = 401,<template>
  278.   
  279. </template><template>
  280.   
  281. </template><template>
  282.   
  283. </template><template>
  284.   
  285. </template><template>
  286.   
  287. </template><template>
  288.   
  289. </template><template>
  290.   
  291. </template><template>
  292.   
  293. </template><template>
  294.   
  295. </template><template>
  296.   
  297. </template><template>
  298.   
  299. </template><template>
  300.   
  301. </template>Message = "NoUsername"<template>
  302.   
  303. </template><template>
  304.   
  305. </template><template>
  306.   
  307. </template><template>
  308.   
  309. </template><template>
  310.   
  311. </template><template>
  312.   
  313. </template><template>
  314.   
  315. </template><template>
  316.   
  317. </template><template>
  318.   
  319. </template><template>
  320.   
  321. </template>};<template>
  322.   
  323. </template><template>
  324.   
  325. </template><template>
  326.   
  327. </template><template>
  328.   
  329. </template><template>
  330.   
  331. </template><template>
  332.   
  333. </template><template>
  334.   
  335. </template><template>
  336.   
  337. </template>}<template>
  338.   
  339. </template><template>
  340.   
  341. </template><template>
  342.   
  343. </template><template>
  344.   
  345. </template><template>
  346.   
  347. </template><template>
  348.   
  349. </template><template>
  350.   
  351. </template><template>
  352.   
  353. </template>if (!Context.User?.IsInRole("user") ?? false)<template>
  354.   
  355. </template><template>
  356.   
  357. </template><template>
  358.   
  359. </template><template>
  360.   
  361. </template><template>
  362.   
  363. </template><template>
  364.   
  365. </template><template>
  366.   
  367. </template><template>
  368.   
  369. </template>{<template>
  370.   
  371. </template><template>
  372.   
  373. </template><template>
  374.   
  375. </template><template>
  376.   
  377. </template><template>
  378.   
  379. </template><template>
  380.   
  381. </template><template>
  382.   
  383. </template><template>
  384.   
  385. </template><template>
  386.   
  387. </template><template>
  388.   
  389. </template>username = "root";<template>
  390.   
  391. </template><template>
  392.   
  393. </template><template>
  394.   
  395. </template><template>
  396.   
  397. </template><template>
  398.   
  399. </template><template>
  400.   
  401. </template><template>
  402.   
  403. </template><template>
  404.   
  405. </template>}<template>
  406.   
  407. </template><template>
  408.   
  409. </template><template>
  410.   
  411. </template><template>
  412.   
  413. </template><template>
  414.   
  415. </template><template>
  416.   
  417. </template><template>
  418.   
  419. </template><template>
  420.   
  421. </template>_logger.LogInformation($"{username}");<template>
  422.   
  423. </template><template>
  424.   
  425. </template><template>
  426.   
  427. </template><template>
  428.   
  429. </template><template>
  430.   
  431. </template><template>
  432.   
  433. </template><template>
  434.   
  435. </template><template>
  436.   
  437. </template>await _sshService.CreateConnectionAsync(Context.ConnectionId, username, height, width);<template>
  438.   
  439. </template><template>
  440.   
  441. </template><template>
  442.   
  443. </template><template>
  444.   
  445. </template><template>
  446.   
  447. </template><template>
  448.   
  449. </template><template>
  450.   
  451. </template><template>
  452.   
  453. </template>return new BaseResponse();<template>
  454.   
  455. </template><template>
  456.   
  457. </template><template>
  458.   
  459. </template><template>
  460.   
  461. </template><template>
  462.   
  463. </template><template>
  464.   
  465. </template>}<template>
  466.   
  467. </template><template>
  468.   
  469. </template><template>
  470.   
  471. </template><template>
  472.   
  473. </template><template>
  474.   
  475. </template><template>
  476.   
  477. </template>catch (InvalidOperationException)<template>
  478.   
  479. </template><template>
  480.   
  481. </template><template>
  482.   
  483. </template><template>
  484.   
  485. </template><template>
  486.   
  487. </template><template>
  488.   
  489. </template>{<template>
  490.   
  491. </template><template>
  492.   
  493. </template><template>
  494.   
  495. </template><template>
  496.   
  497. </template><template>
  498.   
  499. </template><template>
  500.   
  501. </template><template>
  502.   
  503. </template><template>
  504.   
  505. </template>return new BaseResponse() { Code = 500, Message = "TerminalAlreadyExist" };<template>
  506.   
  507. </template><template>
  508.   
  509. </template><template>
  510.   
  511. </template><template>
  512.   
  513. </template><template>
  514.   
  515. </template><template>
  516.   
  517. </template>}<template>
  518.   
  519. </template><template>
  520.   
  521. </template><template>
  522.   
  523. </template><template>
  524.   
  525. </template><template>
  526.   
  527. </template><template>
  528.   
  529. </template>catch (Exception e)<template>
  530.   
  531. </template><template>
  532.   
  533. </template><template>
  534.   
  535. </template><template>
  536.   
  537. </template><template>
  538.   
  539. </template><template>
  540.   
  541. </template>{<template>
  542.   
  543. </template><template>
  544.   
  545. </template><template>
  546.   
  547. </template><template>
  548.   
  549. </template><template>
  550.   
  551. </template><template>
  552.   
  553. </template><template>
  554.   
  555. </template><template>
  556.   
  557. </template>_logger.LogError(e, "ConnectionId: {ConnectionId} No such pty session.", Context.ConnectionId);<template>
  558.   
  559. </template><template>
  560.   
  561. </template><template>
  562.   
  563. </template><template>
  564.   
  565. </template><template>
  566.   
  567. </template><template>
  568.   
  569. </template><template>
  570.   
  571. </template><template>
  572.   
  573. </template>return new BaseResponse() { Code = 500, Message = "UnableToCreateTerminal" };<template>
  574.   
  575. </template><template>
  576.   
  577. </template><template>
  578.   
  579. </template><template>
  580.   
  581. </template><template>
  582.   
  583. </template><template>
  584.   
  585. </template>}<template>
  586.   
  587. </template><template>
  588.   
  589. </template><template>
  590.   
  591. </template><template>
  592.   
  593. </template>}<template>
  594.   
  595. </template><template>
  596.   
  597. </template><template>
  598.   
  599. </template><template>
  600.   
  601. </template>///<template>
  602.   
  603. </template><template>
  604.   
  605. </template><template>
  606.   
  607. </template><template>
  608.   
  609. </template> /// 读取输入数据<template>
  610.   
  611. </template><template>
  612.   
  613. </template><template>
  614.   
  615. </template><template>
  616.   
  617. </template>///<template>
  618.   
  619. </template><template>
  620.   
  621. </template><template>
  622.   
  623. </template><template>
  624.   
  625. </template> ///<template>
  626.   
  627. </template><template>
  628.   
  629. </template><template>
  630.   
  631. </template><template>
  632.   
  633. </template> ///<template>
  634.   
  635. </template><template>
  636.   
  637. </template><template>
  638.   
  639. </template><template>
  640.   
  641. </template> public async Task ReadDataAsync(string data)<template>
  642.   
  643. </template><template>
  644.   
  645. </template><template>
  646.   
  647. </template><template>
  648.   
  649. </template>{<template>
  650.   
  651. </template><template>
  652.   
  653. </template><template>
  654.   
  655. </template><template>
  656.   
  657. </template><template>
  658.   
  659. </template><template>
  660.   
  661. </template>try<template>
  662.   
  663. </template><template>
  664.   
  665. </template><template>
  666.   
  667. </template><template>
  668.   
  669. </template><template>
  670.   
  671. </template><template>
  672.   
  673. </template>{<template>
  674.   
  675. </template><template>
  676.   
  677. </template><template>
  678.   
  679. </template><template>
  680.   
  681. </template><template>
  682.   
  683. </template><template>
  684.   
  685. </template><template>
  686.   
  687. </template><template>
  688.   
  689. </template>await _sshService.ReadDataAsync(Context.ConnectionId, data);<template>
  690.   
  691. </template><template>
  692.   
  693. </template><template>
  694.   
  695. </template><template>
  696.   
  697. </template><template>
  698.   
  699. </template><template>
  700.   
  701. </template><template>
  702.   
  703. </template><template>
  704.   
  705. </template>return new BaseResponse();<template>
  706.   
  707. </template><template>
  708.   
  709. </template><template>
  710.   
  711. </template><template>
  712.   
  713. </template><template>
  714.   
  715. </template><template>
  716.   
  717. </template>}<template>
  718.   
  719. </template><template>
  720.   
  721. </template><template>
  722.   
  723. </template><template>
  724.   
  725. </template><template>
  726.   
  727. </template><template>
  728.   
  729. </template>catch (Exception e)<template>
  730.   
  731. </template><template>
  732.   
  733. </template><template>
  734.   
  735. </template><template>
  736.   
  737. </template><template>
  738.   
  739. </template><template>
  740.   
  741. </template>{<template>
  742.   
  743. </template><template>
  744.   
  745. </template><template>
  746.   
  747. </template><template>
  748.   
  749. </template><template>
  750.   
  751. </template><template>
  752.   
  753. </template><template>
  754.   
  755. </template><template>
  756.   
  757. </template>_logger.LogError(e, "ConnectionId: {ConnectionId} No such pty session.", Context.ConnectionId);<template>
  758.   
  759. </template><template>
  760.   
  761. </template><template>
  762.   
  763. </template><template>
  764.   
  765. </template><template>
  766.   
  767. </template><template>
  768.   
  769. </template><template>
  770.   
  771. </template><template>
  772.   
  773. </template>return new BaseResponse { Message = "NoSuchSeesion", Code = 400 };<template>
  774.   
  775. </template><template>
  776.   
  777. </template><template>
  778.   
  779. </template><template>
  780.   
  781. </template><template>
  782.   
  783. </template><template>
  784.   
  785. </template>}<template>
  786.   
  787. </template><template>
  788.   
  789. </template><template>
  790.   
  791. </template><template>
  792.   
  793. </template>}<template>
  794.   
  795. </template><template>
  796.   
  797. </template>}<template>
  798.   
  799. </template><template>
  800.   
  801. </template>///<template>
  802.   
  803. </template><template>
  804.   
  805. </template> /// 客户端接口<template>
  806.   
  807. </template><template>
  808.   
  809. </template>///<template>
  810.   
  811. </template><template>
  812.   
  813. </template> public interface ISshHubClient<template>
  814.   
  815. </template><template>
  816.   
  817. </template>{<template>
  818.   
  819. </template><template>
  820.   
  821. </template><template>
  822.   
  823. </template><template>
  824.   
  825. </template>///<template>
  826.   
  827. </template><template>
  828.   
  829. </template><template>
  830.   
  831. </template><template>
  832.   
  833. </template> /// 写入输出数据<template>
  834.   
  835. </template><template>
  836.   
  837. </template><template>
  838.   
  839. </template><template>
  840.   
  841. </template>///<template>
  842.   
  843. </template><template>
  844.   
  845. </template><template>
  846.   
  847. </template><template>
  848.   
  849. </template> ///<template>
  850.   
  851. </template><template>
  852.   
  853. </template><template>
  854.   
  855. </template><template>
  856.   
  857. </template> ///<template>
  858.   
  859. </template><template>
  860.   
  861. </template><template>
  862.   
  863. </template><template>
  864.   
  865. </template> Task WriteDataAsync(string data);<template>
  866.   
  867. </template><template>
  868.   
  869. </template><template>
  870.   
  871. </template><template>
  872.   
  873. </template>///<template>
  874.   
  875. </template><template>
  876.   
  877. </template><template>
  878.   
  879. </template><template>
  880.   
  881. </template> /// 写入错误数据<template>
  882.   
  883. </template><template>
  884.   
  885. </template><template>
  886.   
  887. </template><template>
  888.   
  889. </template>///<template>
  890.   
  891. </template><template>
  892.   
  893. </template><template>
  894.   
  895. </template><template>
  896.   
  897. </template> ///<template>
  898.   
  899. </template><template>
  900.   
  901. </template><template>
  902.   
  903. </template><template>
  904.   
  905. </template> ///<template>
  906.   
  907. </template><template>
  908.   
  909. </template><template>
  910.   
  911. </template><template>
  912.   
  913. </template> Task WriteErrorAsync(string data);<template>
  914.   
  915. </template><template>
  916.   
  917. </template>}
复制代码
参考文献


来源:https://www.cnblogs.com/aobaxu/archive/2023/10/31/17799346.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具