Java - 使用 JSch 到 mysql 数据库的 ssh 隧道
Java - ssh-tunneling to mysqldatabase with JSch
我已经尝试通过 Google 和 Whosebug 搜索解决方案。有很多关于此的主题,但还没有帮助我。
import java.util.logging.Level;
import java.util.logging.Logger;
public class GTEVDatabaseConnection {
private Connection connection = null;
private static final int DATABASE_PORT = 3306,
LOCAL_PORT = 1234,
SSH_PORT = 22;
private static final String DRIVER = "com.mysql.jdbc.Driver",
DATABASE = "myDatabase",
DATABASE_USER = "dbuser",
DATABASE_PASSWORD = "dbpasswd",
DATABASE_HOST = "example.de.mysql",
SSH_HOST = "ssh.example.de",
LOCAL_DATABASE_URL = "jdbc:mysql://localhost:" + LOCAL_PORT + "/" + DATABASE;
public GTEVDatabaseConnection(String sshUsername, String sshPassword) throws SQLException {
Session sshSession = null;
try {
sshSession = new JSch().getSession(sshUsername, SSH_HOST, SSH_PORT);
sshSession.setPassword(sshPassword);
sshSession.setConfig("StrictHostKeyChecking", "no");
sshSession.connect();
sshSession.setPortForwardingL(LOCAL_PORT, DATABASE_HOST, DATABASE_PORT);
//sshSession.setPortForwardingR(DATABASE_PORT, "localhost", LOCAL_PORT);
Class.forName(DRIVER);
this.connection = DriverManager.getConnection(LOCAL_DATABASE_URL, DATABASE_USER, DATABASE_PASSWORD); //TODO com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
} catch (ClassNotFoundException | JSchException ex) {
Logger.getLogger(GTEVDatabaseConnection.class.getName()).log(Level.SEVERE,null, ex);
} finally {
if(this.connection != null){
connection.close();
}
if(sshSession != null && sshSession.isConnected()){
sshSession.disconnect();
}
}
}
public ResultSet execQuery(String query) throws SQLException {
return this.connection.createStatement().executeQuery(query);
}
}
代码应该做什么:
您应该能够创建 GTEVDatabaseConnection 的对象。构造函数的参数是 ssh-login 的用户名和密码。您需要此登录名才能连接到我的 MySql-数据库,因为您只能通过 ssh 访问它。
因此,当创建一个新对象时,它会在 jsch.getSession(..) 上创建一个新会话,连接并将 PortForwarding 设置为本地主机。
当我尝试执行 DriverManager.getConnection(...) 时发生错误。
这是错误:
SCHWERWIEGEND: null
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:389)
at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1038)
at com.mysql.jdbc.MysqlIO.readPacket(MysqlIO.java:627)
at com.mysql.jdbc.MysqlIO.doHandshake(MysqlIO.java:1013)
at com.mysql.jdbc.ConnectionImpl.coreConnect(ConnectionImpl.java:2239)
at com.mysql.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2270)
at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2069)
at com.mysql.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:794)
at com.mysql.jdbc.JDBC4Connection.<init>(JDBC4Connection.java:44)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:389)
at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:399)
at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:325)
at java.sql.DriverManager.getConnection(DriverManager.java:664)
at java.sql.DriverManager.getConnection(DriverManager.java:247)
at connection.GTEVDatabaseConnection.<init>(GTEVDatabaseConnection.java:44)
at gui.DatabaseConnector.createConnection(DatabaseConnector.java:102)
at gui.DatabaseConnector.lambda$start[=12=](DatabaseConnector.java:50)
at gui.DatabaseConnector$$Lambda/2106702206.handle(Unknown Source)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Node.fireEvent(Node.java:8390)
at javafx.scene.control.Button.fire(Button.java:185)
at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase.handle(BehaviorSkinBase.java:96)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase.handle(BehaviorSkinBase.java:89)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3758)
at javafx.scene.Scene$MouseHandler.access00(Scene.java:3486)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2495)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:350)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:275)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent0(GlassViewEventHandler.java:385)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$$Lambda0/973574965.get(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:404)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:384)
at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
at com.sun.glass.ui.View.notifyMouse(View.java:927)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null5(WinApplication.java:101)
at com.sun.glass.ui.win.WinApplication$$Lambda/1963387170.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.
at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:2914)
at com.mysql.jdbc.MysqlIO.readPacket(MysqlIO.java:559)
... 68 more
感谢您的帮助。当我错过了什么时询问更多细节。
问候追踪器
我发现了错误。服务器的防火墙正在阻止 ssh 隧道。所以我创建了以下有效的代码。
package connection;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
public class GTEVDatabaseConnection {
private final Channel channel;
private static final int SSH_PORT = 22;
private static final String DATABASE = "databasename",
DATABASE_USER = "databaseuser",
DATABASE_PASSWORD = "databasepasswd",
DATABASE_HOST = "databasehost",
SSH_HOST = "sshhost";
public GTEVDatabaseConnection(String sshUsername, String sshPassword) {
try {
Session sshSession = createSshSession(sshUsername, sshPassword);
this.channel = sshSession.openChannel("exec");
((ChannelExec) channel).setErrStream(System.err);
} catch (JSchException ex) {
Logger.getLogger(GTEVDatabaseConnection.class.getName()).log(Level.SEVERE, null, ex);
throw new SQLException("username or password didn´t work");
}
}
/**
* Führt eine SQL-Abfrage aus und liefert eine Tabelle der Ergebnisse
* @param query Der SQL-Code
* @return Tabelle der Ergebnisse. Erste Dimension = Zeile; zweite Dimension = Spalte
* @throws SQLException Tritt auf, wenn der SQL-Befehl eine Fehler auslöste. (Fehler wird per System.err.println(...) ausgegeben)
*/
public ArrayList<ArrayList<String>> execQuery(String query) throws SQLException {
ArrayList<ArrayList<String>> formattedResult = null;
try {
((ChannelExec) channel).setCommand("mysql -u" + DATABASE_USER + " -p" + DATABASE_PASSWORD + " -h" + DATABASE_HOST + " -e'" + query + "' " + DATABASE);
InputStream in = channel.getInputStream();
channel.connect();
//TODO check whether sqlcode is correct
String result = readResult(in);
if(result == null){
throw new SQLException("Invalid SQL-Code");
}
formattedResult = new ArrayList<>();
for(String row: result.split("\n")){
ArrayList<String> fields = new ArrayList<>();
fields.addAll(Arrays.asList(row.split("\t")));
formattedResult.add(fields);
}
channel.disconnect();
} catch (JSchException | IOException ex) {
Logger.getLogger(GTEVDatabaseConnection.class.getName()).log(Level.SEVERE, null, ex);
}
return formattedResult;
}
private String readResult(InputStream in) throws IOException {
if (in.available() <= 0) {
return null;
}
StringBuilder output = new StringBuilder();
int nextByte;
do {
nextByte = in.read();
output.append((char) nextByte);
} while (nextByte != -1);
return output.toString();
}
private Session createSshSession(String sshUsername, String sshPassword) throws JSchException {
Session session = new JSch().getSession(sshUsername, SSH_HOST, SSH_PORT);
session.setPassword(sshPassword);
session.setConfig("StrictHostKeyChecking", "no");
session.connect();
return session;
}
}
现在程序通过 ssh 连接,执行 mysql 命令并读出结果。
它可能不太专业,或者 "nice" 因为我不能使用 ResultSet 来迭代我的结果,但它有效。
为了通过 telnet 连接,我尝试了不同的方法。
- 当我不 运行 程序时,出现预期的连接错误。
- 当我 运行 程序并暂停它以执行
telnet localhost 1234
然后 cmd 被清除并且没有响应。
- 当我尝试输入内容时,命令提示符再次出现。所以我只认为有联系...
我已经尝试通过 Google 和 Whosebug 搜索解决方案。有很多关于此的主题,但还没有帮助我。
import java.util.logging.Level;
import java.util.logging.Logger;
public class GTEVDatabaseConnection {
private Connection connection = null;
private static final int DATABASE_PORT = 3306,
LOCAL_PORT = 1234,
SSH_PORT = 22;
private static final String DRIVER = "com.mysql.jdbc.Driver",
DATABASE = "myDatabase",
DATABASE_USER = "dbuser",
DATABASE_PASSWORD = "dbpasswd",
DATABASE_HOST = "example.de.mysql",
SSH_HOST = "ssh.example.de",
LOCAL_DATABASE_URL = "jdbc:mysql://localhost:" + LOCAL_PORT + "/" + DATABASE;
public GTEVDatabaseConnection(String sshUsername, String sshPassword) throws SQLException {
Session sshSession = null;
try {
sshSession = new JSch().getSession(sshUsername, SSH_HOST, SSH_PORT);
sshSession.setPassword(sshPassword);
sshSession.setConfig("StrictHostKeyChecking", "no");
sshSession.connect();
sshSession.setPortForwardingL(LOCAL_PORT, DATABASE_HOST, DATABASE_PORT);
//sshSession.setPortForwardingR(DATABASE_PORT, "localhost", LOCAL_PORT);
Class.forName(DRIVER);
this.connection = DriverManager.getConnection(LOCAL_DATABASE_URL, DATABASE_USER, DATABASE_PASSWORD); //TODO com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
} catch (ClassNotFoundException | JSchException ex) {
Logger.getLogger(GTEVDatabaseConnection.class.getName()).log(Level.SEVERE,null, ex);
} finally {
if(this.connection != null){
connection.close();
}
if(sshSession != null && sshSession.isConnected()){
sshSession.disconnect();
}
}
}
public ResultSet execQuery(String query) throws SQLException {
return this.connection.createStatement().executeQuery(query);
}
}
代码应该做什么:
您应该能够创建 GTEVDatabaseConnection 的对象。构造函数的参数是 ssh-login 的用户名和密码。您需要此登录名才能连接到我的 MySql-数据库,因为您只能通过 ssh 访问它。
因此,当创建一个新对象时,它会在 jsch.getSession(..) 上创建一个新会话,连接并将 PortForwarding 设置为本地主机。
当我尝试执行 DriverManager.getConnection(...) 时发生错误。
这是错误:
SCHWERWIEGEND: null
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:389)
at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1038)
at com.mysql.jdbc.MysqlIO.readPacket(MysqlIO.java:627)
at com.mysql.jdbc.MysqlIO.doHandshake(MysqlIO.java:1013)
at com.mysql.jdbc.ConnectionImpl.coreConnect(ConnectionImpl.java:2239)
at com.mysql.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2270)
at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2069)
at com.mysql.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:794)
at com.mysql.jdbc.JDBC4Connection.<init>(JDBC4Connection.java:44)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:389)
at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:399)
at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:325)
at java.sql.DriverManager.getConnection(DriverManager.java:664)
at java.sql.DriverManager.getConnection(DriverManager.java:247)
at connection.GTEVDatabaseConnection.<init>(GTEVDatabaseConnection.java:44)
at gui.DatabaseConnector.createConnection(DatabaseConnector.java:102)
at gui.DatabaseConnector.lambda$start[=12=](DatabaseConnector.java:50)
at gui.DatabaseConnector$$Lambda/2106702206.handle(Unknown Source)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Node.fireEvent(Node.java:8390)
at javafx.scene.control.Button.fire(Button.java:185)
at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase.handle(BehaviorSkinBase.java:96)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase.handle(BehaviorSkinBase.java:89)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3758)
at javafx.scene.Scene$MouseHandler.access00(Scene.java:3486)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2495)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:350)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:275)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent0(GlassViewEventHandler.java:385)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$$Lambda0/973574965.get(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:404)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:384)
at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
at com.sun.glass.ui.View.notifyMouse(View.java:927)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null5(WinApplication.java:101)
at com.sun.glass.ui.win.WinApplication$$Lambda/1963387170.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.
at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:2914)
at com.mysql.jdbc.MysqlIO.readPacket(MysqlIO.java:559)
... 68 more
感谢您的帮助。当我错过了什么时询问更多细节。 问候追踪器
我发现了错误。服务器的防火墙正在阻止 ssh 隧道。所以我创建了以下有效的代码。
package connection;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
public class GTEVDatabaseConnection {
private final Channel channel;
private static final int SSH_PORT = 22;
private static final String DATABASE = "databasename",
DATABASE_USER = "databaseuser",
DATABASE_PASSWORD = "databasepasswd",
DATABASE_HOST = "databasehost",
SSH_HOST = "sshhost";
public GTEVDatabaseConnection(String sshUsername, String sshPassword) {
try {
Session sshSession = createSshSession(sshUsername, sshPassword);
this.channel = sshSession.openChannel("exec");
((ChannelExec) channel).setErrStream(System.err);
} catch (JSchException ex) {
Logger.getLogger(GTEVDatabaseConnection.class.getName()).log(Level.SEVERE, null, ex);
throw new SQLException("username or password didn´t work");
}
}
/**
* Führt eine SQL-Abfrage aus und liefert eine Tabelle der Ergebnisse
* @param query Der SQL-Code
* @return Tabelle der Ergebnisse. Erste Dimension = Zeile; zweite Dimension = Spalte
* @throws SQLException Tritt auf, wenn der SQL-Befehl eine Fehler auslöste. (Fehler wird per System.err.println(...) ausgegeben)
*/
public ArrayList<ArrayList<String>> execQuery(String query) throws SQLException {
ArrayList<ArrayList<String>> formattedResult = null;
try {
((ChannelExec) channel).setCommand("mysql -u" + DATABASE_USER + " -p" + DATABASE_PASSWORD + " -h" + DATABASE_HOST + " -e'" + query + "' " + DATABASE);
InputStream in = channel.getInputStream();
channel.connect();
//TODO check whether sqlcode is correct
String result = readResult(in);
if(result == null){
throw new SQLException("Invalid SQL-Code");
}
formattedResult = new ArrayList<>();
for(String row: result.split("\n")){
ArrayList<String> fields = new ArrayList<>();
fields.addAll(Arrays.asList(row.split("\t")));
formattedResult.add(fields);
}
channel.disconnect();
} catch (JSchException | IOException ex) {
Logger.getLogger(GTEVDatabaseConnection.class.getName()).log(Level.SEVERE, null, ex);
}
return formattedResult;
}
private String readResult(InputStream in) throws IOException {
if (in.available() <= 0) {
return null;
}
StringBuilder output = new StringBuilder();
int nextByte;
do {
nextByte = in.read();
output.append((char) nextByte);
} while (nextByte != -1);
return output.toString();
}
private Session createSshSession(String sshUsername, String sshPassword) throws JSchException {
Session session = new JSch().getSession(sshUsername, SSH_HOST, SSH_PORT);
session.setPassword(sshPassword);
session.setConfig("StrictHostKeyChecking", "no");
session.connect();
return session;
}
}
现在程序通过 ssh 连接,执行 mysql 命令并读出结果。
它可能不太专业,或者 "nice" 因为我不能使用 ResultSet 来迭代我的结果,但它有效。
为了通过 telnet 连接,我尝试了不同的方法。
- 当我不 运行 程序时,出现预期的连接错误。
- 当我 运行 程序并暂停它以执行
telnet localhost 1234
然后 cmd 被清除并且没有响应。 - 当我尝试输入内容时,命令提示符再次出现。所以我只认为有联系...