You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

JchService.java 8.4 kB

2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. package com.educoder.bridge.service;
  2. import com.alibaba.fastjson.JSONObject;
  3. import com.educoder.bridge.model.SSHInfo;
  4. import com.educoder.bridge.model.SSHSession;
  5. import com.educoder.bridge.utils.Base64Util;
  6. import com.jcraft.jsch.ChannelShell;
  7. import com.jcraft.jsch.JSch;
  8. import com.jcraft.jsch.Session;
  9. import com.jcraft.jsch.UserInfo;
  10. import org.slf4j.Logger;
  11. import org.slf4j.LoggerFactory;
  12. import org.springframework.stereotype.Service;
  13. import org.springframework.web.socket.TextMessage;
  14. import org.springframework.web.socket.WebSocketSession;
  15. import java.io.IOException;
  16. import java.io.InputStream;
  17. import java.io.OutputStream;
  18. import java.util.Arrays;
  19. import java.util.List;
  20. import java.util.Optional;
  21. import java.util.concurrent.CopyOnWriteArrayList;
  22. import java.util.concurrent.ExecutorService;
  23. import java.util.concurrent.Executors;
  24. @Service
  25. public class JchService {
  26. private static List<SSHSession> sshSessionQueue = new CopyOnWriteArrayList<>();
  27. private ExecutorService executorService = Executors.newCachedThreadPool();
  28. private Logger logger = LoggerFactory.getLogger(getClass());
  29. com.jcraft.jsch.Logger jschLogger = new com.jcraft.jsch.Logger() {
  30. @Override
  31. public boolean isEnabled(int arg0) {
  32. return true;
  33. }
  34. @Override
  35. public void log(int arg0, String arg1) {
  36. if (logger.isTraceEnabled()) {
  37. logger.trace("JSch Log [Level " + arg0 + "]: " + arg1);
  38. }
  39. }
  40. };
  41. /**
  42. * 在webSocket连接时,初始化一个ssh连接
  43. *
  44. * @param webSocketSession webSocket连接
  45. */
  46. public void add(WebSocketSession webSocketSession) {
  47. SSHSession sshSession = new SSHSession();
  48. sshSession.setWebSocketSession(webSocketSession);
  49. sshSessionQueue.add(sshSession);
  50. }
  51. /**
  52. * 处理客户端发过来的数据
  53. * @param buffer 数据
  54. * @param webSocketSession webSocket连接
  55. */
  56. public void recv(String buffer, WebSocketSession webSocketSession) {
  57. SSHSession sshSession = null;
  58. try {
  59. logger.debug("webSocketSessionID: {}, 信息: {}", webSocketSession.getId(), buffer);
  60. JSONObject info = JSONObject.parseObject(buffer);
  61. String tp = info.getString("tp");
  62. sshSession = findByWebSocketSession(webSocketSession);
  63. //初始化连接
  64. if ("init".equals(tp)) {
  65. // {"tp":"init","data":{"host":"127.0.0.1","port":"41080","username":"root","password":"123123"}}
  66. SSHInfo sshInfo = info.getObject("data", SSHInfo.class);
  67. sshSession.setSSHInfo(sshInfo);
  68. if (sshSession != null) {
  69. SSHSession finalSSHSession = sshSession;
  70. // 新开一个线程建立连接,连接开启之后以一直监听来自客户端的输入
  71. executorService.execute(() -> {
  72. connectTossh(finalSSHSession);
  73. });
  74. }
  75. } else if ("client".equals(tp)) {
  76. String data = info.getString("data");
  77. // 将网页输入的数据传送给后端服务器
  78. if (sshSession != null) {
  79. transTossh(sshSession.getOutputStream(), data);
  80. }
  81. }
  82. } catch (Exception e) {
  83. logger.error("转发命令到ssh出错: {}", e);
  84. close(sshSession);
  85. }
  86. }
  87. /**
  88. * 将数据传送给服务端作为SSH的输入
  89. *
  90. * @param outputStream
  91. * @param data
  92. * @throws IOException
  93. */
  94. private void transTossh(OutputStream outputStream, String data) throws IOException {
  95. if (outputStream != null) {
  96. outputStream.write(data.getBytes());
  97. outputStream.flush();
  98. }
  99. }
  100. /**
  101. * 连接ssh
  102. *
  103. * @param sshSession ssh连接需要的信息
  104. */
  105. private void connectTossh(SSHSession sshSession){
  106. Session jschSession = null;
  107. SSHInfo SSHInfo = sshSession.getSSHInfo();
  108. try {
  109. JSch jsch = new JSch();
  110. JSch.setLogger(jschLogger);
  111. //启动线程
  112. java.util.Properties config = new java.util.Properties();
  113. config.put("StrictHostKeyChecking", "no");
  114. jschSession = jsch.getSession(SSHInfo.getUsername(), SSHInfo.getHost(), SSHInfo.getPort());
  115. jschSession.setConfig(config);
  116. jschSession.setPassword(SSHInfo.getPassword());
  117. jschSession.setUserInfo(new UserInfo() {
  118. @Override
  119. public String getPassphrase() {
  120. return null;
  121. }
  122. @Override
  123. public String getPassword() {
  124. return null;
  125. }
  126. @Override
  127. public boolean promptPassword(String s) {
  128. return false;
  129. }
  130. @Override
  131. public boolean promptPassphrase(String s) {
  132. return false;
  133. }
  134. @Override
  135. public boolean promptYesNo(String s) {
  136. return true;
  137. } // Accept all server keys
  138. @Override
  139. public void showMessage(String s) {
  140. }
  141. });
  142. jschSession.connect();
  143. ChannelShell channel = (ChannelShell) jschSession.openChannel("shell");
  144. channel.setPtyType("xterm");
  145. channel.connect();
  146. sshSession.setChannel(channel);
  147. InputStream inputStream = channel.getInputStream();
  148. sshSession.setOutputStream(channel.getOutputStream());
  149. sshSession.setSSHInfo(SSHInfo);
  150. logger.debug("主机: {} 连接成功!", SSHInfo.getHost());
  151. // 循环读取,jsch的输入为服务器执行命令之后的返回数据
  152. byte[] buf = new byte[1024];
  153. while (true) {
  154. int length = inputStream.read(buf);
  155. if (length < 0) {
  156. close(sshSession);
  157. throw new Exception("读取出错,数据长度:" + length);
  158. }
  159. sendMsg(sshSession.getWebSocketSession(), Arrays.copyOfRange(buf, 0, length));
  160. }
  161. } catch (Exception e) {
  162. logger.error("ssh连接出错, e: {}", e);
  163. } finally {
  164. logger.info("连接关闭, {}", SSHInfo.getHost());
  165. if (jschSession != null) {
  166. jschSession.disconnect();
  167. }
  168. close(sshSession);
  169. }
  170. }
  171. /**
  172. * 发送数据回websocket
  173. *
  174. * @param webSocketSession webSocket连接
  175. * @param buffer 数据
  176. * @throws IOException
  177. */
  178. public void sendMsg(WebSocketSession webSocketSession, byte[] buffer) throws IOException {
  179. logger.debug("服务端返回的数据: {}", new String(buffer, "UTF-8"));
  180. webSocketSession.sendMessage(new TextMessage(Base64Util.encodeBytes(buffer)));
  181. }
  182. /**
  183. * 通过webSocket连接在队列中找到对应的SSH连接
  184. *
  185. * @param webSocketSession webSocket连接
  186. */
  187. public SSHSession findByWebSocketSession(WebSocketSession webSocketSession) {
  188. Optional<SSHSession> optional = sshSessionQueue.stream().filter(webscoketObj -> webscoketObj.getWebSocketSession() == webSocketSession).findFirst();
  189. if (optional.isPresent()) {
  190. return optional.get();
  191. }
  192. return null;
  193. }
  194. /**
  195. * 关闭ssh和websocket连接
  196. *
  197. * @param sshSession ssh连接
  198. */
  199. private void close(SSHSession sshSession) {
  200. if (sshSession != null) {
  201. sshSession.getChannel().disconnect();
  202. try {
  203. sshSession.getWebSocketSession().close();
  204. sshSession.getOutputStream().close();
  205. } catch (IOException e) {
  206. logger.error("连接关闭失败!e: {}", e);
  207. }
  208. sshSessionQueue.remove(sshSession);
  209. }
  210. }
  211. /**
  212. * 通过webSocketSession关闭ssh与webSocket连接
  213. *
  214. * @param webSocketSession
  215. */
  216. public void closeByWebSocket(WebSocketSession webSocketSession) {
  217. close(findByWebSocketSession(webSocketSession));
  218. }
  219. }

人工智能研发终端

Contributors (1)