我试图通过SSH隧道(JSch)连接到我的Linux服务器上的MySQL服务器(JDBC),但我总是得到一个
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.
Caused by: java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.
奇怪的是,当我尝试使用相同设置连接图形客户端(例如Sequel Pro)时,我没有任何问题。这是I级工作的片段,供参考:
private DatabaseManager(Logger logger, Configuration config) {
this.logger = logger;
this.marker = MarkerFactory.getMarker(this.getClass().getSimpleName());
try {
sshTunnel = config.get(EnvironmentSetting.SSH_TUNNEL, Boolean.TYPE);
databaseHost = config.get(EnvironmentSetting.DATABASE, String.class);
databasePort = config.get(EnvironmentSetting.DATABASE_PORT, Integer.TYPE);
databaseUser = config.get(EnvironmentSetting.DATABASE_USER, String.class);
databasePassword = config.get(EnvironmentSetting.DATABASE_PASSWORD, String.class);
database = config.get(EnvironmentSetting.DATABASE, String.class);
Preconditions.checkNotNull(this, "Basic database configuration must be set", sshTunnel,
databaseHost, databasePort, databaseUser, databasePassword, database);
if (sshTunnel) {
sshHost = config.get(EnvironmentSetting.REMOTE_IP, String.class);
sshPort = config.get(EnvironmentSetting.REMOTE_PORT, Integer.TYPE);
sshUser = config.get(EnvironmentSetting.REMOTE_USER, String.class);
sshKeyPath = config.get(EnvironmentSetting.LOCAL_KEY, String.class);
sshKeyPassword = config.get(EnvironmentSetting.LOCAL_KEY_PASSWORD, String.class);
localBindPort = config.get(EnvironmentSetting.LOCAL_PORT, Integer.TYPE);
Preconditions.checkNotNull(this, "SSH tunnel settings must be set if enabled", sshHost,
sshPort, sshUser, sshKeyPath, localBindPort);
connectSshTunnel();
}
} catch (ConfigurationValueNotFoundException e) {
e.printStackTrace();
logger.warn(marker, e.getMessage());
logger.warn(marker, "Unable to use config values");
}
MysqlDataSource dataSource = new MysqlDataSource();
dataSource.setServerName(sshTunnel ? "localhost" : databaseHost);
dataSource.setPort(sshTunnel ? localBindPort : databasePort);
dataSource.setDatabaseName(database);
dataSource.setUser(databaseUser);
dataSource.setPassword(databasePassword);
this.dataSource = dataSource;
// Connection test
try {
Connection connection = dataSource.getConnection();
String catalog = connection.getCatalog();
logger.info(marker, catalog);
} catch (SQLException e) {
e.printStackTrace();
}
}
private void connectSshTunnel() {
try {
final JSch jsch = new JSch();
session = jsch.getSession(sshUser, sshHost, sshPort);
jsch.addIdentity(FileUtil.cleanFile(sshKeyPath), !sshKeyPassword.equals("") ? sshKeyPassword
: null);
final Properties config = new Properties();
config.put("StrictHostKeyChecking", "no" );
session.setConfig(config);
session.connect();
logger.info(marker, "Successfully connected SSH tunnel");
final int assignedPort = session.setPortForwardingL(localBindPort, sshHost, databasePort);
logger.info(marker, String.format("Port forwarded: localhost:%d -> %s:%d", assignedPort, sshHost, databasePort));
} catch (JSchException e) {
e.printStackTrace();
logger.warn(marker, e.getMessage());
logger.warn(marker, "Failed to setup JSch");
}
}