java - SSH 服务器-客户端通信,来自套接字的读写流
问题描述
基本上,我需要进行一种聊天。我已经设置了 JSch 库并使用他们的示例,我能够成功地打开客户端(Win10-local)和服务器(Rpi-remote)之间的 SSH(-R)隧道。我可以在 rpi 中向 shell 发送命令、传递文件、创建新文件、写入它们等等......但我需要能够“捕获”并直接从套接字读取服务器端的数据,假设发送了一些字符串从客户端。然后我必须在服务器端更改此字符串并将其重新发送回客户端,然后将其打印出来。
我尝试创建一个套接字(服务器)并绑定到 SSH 通信所在的端口,但我收到一个错误,即套接字无法绑定到该端口,因为它已被使用。如果我先绑定套接字,那么 SSH 隧道将不会通过。
我还尝试了 jsch 示例中的守护进程示例: http ://www.jcraft.com/jsch/examples/Daemon.java.html 但没有任何成功。
现在我正在尝试在服务器端使用此代码:
public class ServerSide {
private final static Random random = new Random();
private final static String[] ADVICE_LIST = {
"Take smaller bites",
"Go for the tight jeans. No they do NOT make you look fat.",
"One word: inappropriate",
};
private void go() throws IOException {
ServerSocket serverSocket = new ServerSocket();
serverSocket.bind(new InetSocketAddress("localhost",12005));
while(!serverSocket.isClosed()) {
Socket socket = serverSocket.accept();
PrintWriter writer = new PrintWriter(socket.getOutputStream());
System.out.println(socket.getOutputStream());
String advice = getAdvice();
System.out.println("Sending advice: " + advice);
writer.write(advice);
writer.close();
System.out.println("Advice sent!");
socket.close();
}
}
private static String getAdvice() {
return ADVICE_LIST[random.nextInt() % ADVICE_LIST.length];
}
public static void main(String[] args) throws IOException {
ServerSide server = new ServerSide();
server.go();
}
}
}
服务器侦听端口 12005,如果它检测到任何客户端,它只会向他发送一条随机消息。当我昨天尝试时,在服务器监听的情况下,无法建立隧道,但是当我尝试时,隧道已经建立,但服务器根本没有检测到任何东西。客户端的代码是:
public class PortForwardingR{
public static void main(String[] arg){
int rport;
String lhost;
int lport;
try{
JSch jsch=new JSch();
String host=null;
if(arg.length>0){
host=arg[0];
}
else{
host=JOptionPane.showInputDialog("Enter username@hostname",
System.getProperty("user.name")+
"@localhost");
}
String user=host.substring(0, host.indexOf('@'));
host=host.substring(host.indexOf('@')+1);
Session session=jsch.getSession(user, host, 22);
String foo=JOptionPane.showInputDialog("Enter -R port:host:hostport",
"port:host:hostport");
rport=Integer.parseInt(foo.substring(0, foo.indexOf(':')));
foo=foo.substring(foo.indexOf(':')+1);
lhost=foo.substring(0, foo.indexOf(':'));
lport=Integer.parseInt(foo.substring(foo.indexOf(':')+1));
// username and password will be given via UserInfo interface.
UserInfo ui=new MyUserInfo();
session.setUserInfo(ui);
session.connect();
// Channel channel=session.openChannel("shell");
// channel.connect();
session.setPortForwardingR(rport, lhost, lport);
System.out.println(host+":"+rport+" -> "+lhost+":"+lport);
}
catch(Exception e){
System.out.println(e);
}
}
public static class MyUserInfo implements UserInfo, UIKeyboardInteractive{
public String getPassword(){ return passwd; }
public boolean promptYesNo(String str){
Object[] options={ "yes", "no" };
int foo=JOptionPane.showOptionDialog(null,
str,
"Warning",
JOptionPane.DEFAULT_OPTION,
JOptionPane.WARNING_MESSAGE,
null, options, options[0]);
return foo==0;
}
String passwd;
JTextField passwordField=(JTextField)new JPasswordField(20);
public String getPassphrase(){ return null; }
public boolean promptPassphrase(String message){ return true; }
public boolean promptPassword(String message){
Object[] ob={passwordField};
int result=
JOptionPane.showConfirmDialog(null, ob, message,
JOptionPane.OK_CANCEL_OPTION);
if(result==JOptionPane.OK_OPTION){
passwd=passwordField.getText();
return true;
}
else{ return false; }
}
public void showMessage(String message){
JOptionPane.showMessageDialog(null, message);
}
final GridBagConstraints gbc =
new GridBagConstraints(0,0,1,1,1,1,
GridBagConstraints.NORTHWEST,
GridBagConstraints.NONE,
new Insets(0,0,0,0),0,0);
private Container panel;
public String[] promptKeyboardInteractive(String destination,
String name,
String instruction,
String[] prompt,
boolean[] echo){
panel = new JPanel();
panel.setLayout(new GridBagLayout());
gbc.weightx = 1.0;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.gridx = 0;
panel.add(new JLabel(instruction), gbc);
gbc.gridy++;
gbc.gridwidth = GridBagConstraints.RELATIVE;
JTextField[] texts=new JTextField[prompt.length];
for(int i=0; i<prompt.length; i++){
gbc.fill = GridBagConstraints.NONE;
gbc.gridx = 0;
gbc.weightx = 1;
panel.add(new JLabel(prompt[i]),gbc);
gbc.gridx = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weighty = 1;
if(echo[i]){
texts[i]=new JTextField(20);
}
else{
texts[i]=new JPasswordField(20);
}
panel.add(texts[i], gbc);
gbc.gridy++;
}
if(JOptionPane.showConfirmDialog(null, panel,
destination+": "+name,
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE)
==JOptionPane.OK_OPTION){
String[] response=new String[prompt.length];
for(int i=0; i<prompt.length; i++){
response[i]=texts[i].getText();
}
return response;
}
else{
return null; // cancel
}
}
}
}
当我提示“输入用户名@主机名”时,我输入 RPI's_username@It's_publicIP,然后在“输入 -R 端口:主机:主机端口”中输入:12005:localhost:12005。我做对了吗?连接成功建立,所以我相信没问题。
另外,我在这里找到了这段代码(尝试过并且有效),它非常接近我想要的,但它适用于 shell,我想在服务器端直接与我的代码通信。
public class TestShell {
public static void main(String[] arg) {
try {
JSch jsch = new JSch();
String host = null;
final Session session = jsch.getSession("user", "remotecomputer", 22);
session.setPassword("fluffybunnyslippers");
session.setConfig("StrictHostKeyChecking", "no");
session.connect(30000); // making a connection with timeout.
final Channel channel = session.openChannel("shell");
PipedInputStream pis = new PipedInputStream();
final PipedOutputStream pos = new PipedOutputStream(pis);
channel.setInputStream(pis);
channel.setOutputStream(new OutputStream() {
private int cmdIndx = 0;
private String[] cmds = {
"ls\n",
"cd ..\n",
"ls\n",
"exit\n"
};
private String line = "";
@Override
public void write(int b) throws IOException {
char c = (char) b;
if (c == '\n') {
logout(line);
System.out.print(line);
line = "";
} else {
line += c;
logout(line);
if (line.endsWith("$ ")) {
String cmd = cmds[cmdIndx];
cmdIndx++;
pos.write(cmd.getBytes());
}
}
}
public void logout(String line) {
if (line.startsWith("logout")) {
System.out.println("...logout...");
channel.disconnect();
session.disconnect();
System.exit(0);
}
}
});
channel.connect(3 * 1000);
} catch (Exception e) {
System.out.println(e);
}
}
}
Rpi(服务器)位于具有公共 IP 的路由器上。路由器在端口 12005 上设置了端口转发,它将数据发送到我的 RPI 所在的本地 IP(和端口 12005)。路由器还具有公开的端口 12005,可能没有必要,如果我实现了我想要的,我会关闭它。客户端只是来自移动热点的 wifi。
有人可以给我一些关于如何使用现有的、工作的、SSH 隧道直接从套接字读取/写入通信的建议吗?我是通过互联网进行交流的初学者。
解决方案
推荐阅读
- javascript - Vuex-ORM 插入和合并两个相互关联的 api 调用
- ajax - 将我自己的 Alexa 购物清单提取到 Bootstrap 表中
- reactjs - 为什么在我不更改我的 useEffect 挂钩的任何依赖项的情况下触发了“exhaustive-deps”规则?
- php - 升级 Laravel 和 PHP 的步骤
- android - 如何提取压缩的rom
- angular - 如何解决日历问题,导致它不选择未来?
- post - 邮递员 - 无法发送 Post Twilio API 请求
- tensorflow - nvidia-smi gpu-util 含义
- android - 如何在新安装的 chromium(for android) 浏览器启动时抑制欢迎说明和登录表单
- spring-boot - javax.jms.JMSException:检测到重复的持久订阅