我正在尝试通过我的Java代码建立SSH连接,但是得到以下异常..我通过Putty / Winscp工具测试了我的连接,它工作正常。问题在于我的Java代码......
SEVERE: The Transport Protocol thread failed
java.io.IOException: The socket is EOF
at com.sshtools.j2ssh.transport.TransportProtocolInputStream.readBufferedData(Unknown Source)
at com.sshtools.j2ssh.transport.TransportProtocolInputStream.readMessage(Unknown Source)
at com.sshtools.j2ssh.transport.TransportProtocolCommon.readMessage(Unknown Source)
at com.sshtools.j2ssh.transport.kex.DhGroup1Sha1.performClientExchange(Unknown Source)
at com.sshtools.j2ssh.transport.TransportProtocolClient.performKeyExchange(Unknown Source)
at com.sshtools.j2ssh.transport.TransportProtocolCommon.beginKeyExchange(Unknown Source)
at com.sshtools.j2ssh.transport.TransportProtocolCommon.onMsgKexInit(Unknown Source)
at com.sshtools.j2ssh.transport.TransportProtocolCommon.startBinaryPacketProtocol(Unknown Source)
at com.sshtools.j2ssh.transport.TransportProtocolCommon.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
下面是我建立连接的Java代码
public class MySSHClient {
static SshClient ssh = null;
static SshConnectionProperties properties = null;
SessionChannelClient session = null;
private static void MySSHClient(String hostName, String userName, String passwd )
{
try
{
// Make a client connection
ssh = new SshClient();
properties = new SshConnectionProperties();
properties.setHost("192.168.1.175");
// Connect to the host
ssh.connect(properties, new IgnoreHostKeyVerification());
// Create a password authentication instance
PasswordAuthenticationClient pwd = new PasswordAuthenticationClient();
pwd.setUsername("root");
pwd.setPassword("123456");
// Try the authentication
int result = ssh.authenticate(pwd);
// Evaluate the result
if (result==AuthenticationProtocolState.COMPLETE) {
System.out.println("Connection Authenticated");
}
}
catch(Exception e)
{
System.out.println("Exception : " + e.getMessage());
}
}//end of method.
public String execCmd(String cmd)
{
String theOutput = "";
try
{
// The connection is authenticated we can now do some real work!
session = ssh.openSessionChannel();
if ( session.executeCommand(cmd) )
{
IOStreamConnector output = new IOStreamConnector();
java.io.ByteArrayOutputStream bos = new
java.io.ByteArrayOutputStream();
output.connect(session.getInputStream(), bos );
session.getState().waitForState(ChannelState.CHANNEL_CLOSED);
theOutput = bos.toString();
}
//else
//throw Exception("Failed to execute command : " + cmd);
//System.out.println("Failed to execute command : " + cmd);
}
catch(Exception e)
{
System.out.println("Exception : " + e.getMessage());
}
return theOutput;
}
public static void main(String[] args){
MySSHClient(null, null, null);
}
答案 0 :(得分:11)
我在调查问题java.io.IOException: The socket is EOF
中的错误时偶然发现了这个问题和答案。因为在我的情况下不能立即更改代码以使用其他SSH Java库,并且@ a3.14_Infinity所述的解释对我来说不够详细,我想补充一下。
因为这个例外不是很有用,所以我首先尝试Wireshark来查看网络上发生了什么,但无济于事。所以我将sshd_config
(OpenSSH 6.9)配置为登录DEBUG3
级别,并在我的测试机器的/var/log/auth.log
文件中得到答案。在尝试与SSH客户端(Java SSH库)协商密钥交换算法时,它声明了 致命错误 。
由于SSH服务器和客户端无法就互密钥交换算法达成一致,因此OpenSSH服务器终止与客户端的连接。因此,Java SSH库代码会抛出异常。
sshtools.j2ssh
(sshtools : j2ssh-core : 0.2.9)库代码非常陈旧且已停止使用。从OpenSSH 6.7(2014年10月发布)开始,默认密码和MAC已被更改,以删除包含blowfish-cbc
密码的不安全算法。使用OpenSSH 6.9(2015年6月发布)默认情况下禁用对1024位diffie-hellman-group1-sha1
密钥交换的支持。
当您仍然使用史前SSH工具j2ssh
库(上帝禁止)连接到较新的OpenSSH服务器时,您将收到所描述的错误。库代码仅向OpenSSH服务器提供diffie-hellman-group1-sha1
密钥交换算法,默认情况下不支持该算法。因此,无法建立安全连接。
如果无法立即转移到另一个Java SSH库(我的情况),那么您可以在OpenSSH的服务器配置文件diffie-hellman-group1-sha1
中重新启用禁用的sshd_config
密钥交换算法。例如像这样。
Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com,chacha20-poly1305@openssh.com,blowfish-cbc
KexAlgorithms diffie-hellman-group1-sha1,diffie-hellman-group-exchange-sha1,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha1
但我要清楚这一点。 diffie-hellman-group1-sha1
密钥交换算法以及blowfish-cbc
密码默认情况下处于关闭状态,因为它们不安全。重新启用它们应该只是一个临时措施,直到您可以替换这个过时的Java SSH库。
最后,我想指出其他答案中建议的 Java安全通道(JSch)库已停止使用。因此,您可能需要考虑sshj甚至ssh2j-maverick。
编辑:我错了, Java安全通道JSch 库还活着(JSCH 0.1.54发布于2016-09-03 {{ 3}})当然值得你考虑。或者,您可能还需要考虑on MavenCentral或sshj。
为了使sshtools.j2ssh
(ssh2j-maverick)库的迁移工作保持最小,我查看了{{ 商业 旧版SSH客户端库{{ 3}}(版本1.7.1)。这允许保留现有的库集成代码,只需对库API和异常处理进行一些微小的更改。因此,如果您不想从头开始重新启动,那么咬住子弹并坚持使用SSHTOOLS可能是您的最佳选择。最后,为了衡量迁移工作,我首先用SSHTOOLS的开源库sshtools : j2ssh-core : 0.2.9替换了库,该库几乎与最新的商业版本(版本1.7.1)具有相同的API。
答案 1 :(得分:1)
当j2ssh.jar文件与当前的SFTP版本不兼容时,会出现此错误("传输协议线程失败.java.io.IOException:套接字是EOF“)服务器
您可以尝试使用here中的Java安全通道(JSch)。
礼貌:http://techydiary.com/the-transport-protocol-thread-failed-java-io-ioexception-the-socket-is-eof/
答案 2 :(得分:0)
以下示例代码可以为您提供帮助,
import java.io.InputStream;
import org.apache.commons.io.IOUtils;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
public class SSHClient {
/**
* Constant EXCUTE_CHANNEL
*/
public static final String EXCUTE_CHANNEL = "exec";
/**
* Constant STRICT_KEY_CHECKING
*/
public static final String STRICT_KEY_CHECKING = "StrictHostKeyChecking";
/** Name/ip of the remote machine/device **/
private String host;
private String userName;
private String password;
/**
* This method used to initilze user and host
*
* @param userName
* @param password
* @param host
*/
public SSHClient(String userName,String password, String host) {
super();
this.userName = userName;
this.password = password;
this.host = host;
}
/**
* This method used to execute commands remotly by using SSHV2
*
* @param host
* @param username
* @param password
* @param command
* @return
*/
public String executeCommand(String command) {
StringBuilder log = new StringBuilder();
String response = null;
Channel channel = null;
Session session = null;
try {
JSch jsch = new JSch();
JSch.setConfig(STRICT_KEY_CHECKING, Constants.NO);
session = jsch.getSession(userName, host, 22);
// If two machines have SSH passwordless logins setup, the following
// line is not needed:
session.setPassword(password);
session.connect();
channel = session.openChannel(EXCUTE_CHANNEL);
((ChannelExec) channel).setCommand(command);
// channel.setInputStream(System.in);
channel.setInputStream(null);
((ChannelExec) channel).setErrStream(System.err);
InputStream in = channel.getInputStream();
channel.connect();
response = IOUtils.toString(in);
} catch (Exception ex) {
//handle exception
} finally {
try {
if (session != null) {
session.disconnect();
}
} catch (Exception ex) {
//handle exception
}
try {
if (channel != null) {
channel.disconnect();
}
} catch (Exception ex) {
//handle exception
}
}
System.ou.println( "Response received :"+ response));
return response;
}
}
答案 3 :(得分:0)
以下是从某些Google来源重复使用的工作代码-
import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.StreamGobbler;
Connection conn = new Connection(server);
conn.connect();
boolean isAuthenticated = conn.authenticateWithPassword(user_id, password);
System.out.println("Is server - " + server + " Authenticated? " + isAuthenticated);
if (isAuthenticated == false)
throw new IOException("Authentication failed.");
ch.ethz.ssh2.Session sess = conn.openSession();
String new_commands = "";
for (int i = 0; i < commands.size(); i++) {
new_commands = new_commands + commands.get(i) + "\n";
}
System.out.println("The command executed is: " + new_commands);
sess.requestDumbPTY();
sess.execCommand(new_commands);
InputStream stdout = new StreamGobbler(sess.getStdout());
BufferedReader br = new BufferedReader(new InputStreamReader(stdout));
InputStream errStrm = new StreamGobbler(sess.getStderr());
BufferedReader stderrRdr = new BufferedReader(new InputStreamReader(errStrm));
sess.getStdin().write("EXIT\n".getBytes());
System.out.println("the output of the command is");
while (true) {
String line_out = br.readLine();
if (line_out == null) {
break;
} else {
System.out.println(line_out);
output_logs.add(line_out);
}
}
while (true) {
String line_error = stderrRdr.readLine();
if (line_error == null) {
break;
} else {
System.out.println(line_error);
output_logs.add(line_error);
}
}
output_logs.add("Exit Code:" + sess.getExitStatus());
System.out.println("ExitCode: " + sess.getExitSignal());
sess.close();
conn.close();