有谁知道一个好的从Java SSH登录的库。
有谁知道一个好的从Java SSH登录的库。
Answers:
在Java的安全通道(JSCH)是一种非常流行的库,Maven的,蚂蚁和Eclipse使用。它是具有BSD样式许可证的开源。
更新:GSOC项目和那里的代码未处于活动状态,但这是:https : //github.com/hierynomus/sshj
hierynomus从2015年初开始担任维护者。这是Github较旧的,不再维护的链接:
https://github.com/shikhar/sshj
有一个GSOC项目:
http://code.google.com/p/commons-net-ssh/
代码质量似乎比JSch更好,后者虽然是完整且可行的实现,但缺少文档。项目页面会发现即将发布的Beta版本,最后一次提交到存储库是在8月中旬。
比较API:
http://code.google.com/p/commons-net-ssh/
SSHClient ssh = new SSHClient();
//ssh.useCompression();
ssh.loadKnownHosts();
ssh.connect("localhost");
try {
ssh.authPublickey(System.getProperty("user.name"));
new SCPDownloadClient(ssh).copy("ten", "/tmp");
} finally {
ssh.disconnect();
}
Session session = null;
Channel channel = null;
try {
JSch jsch = new JSch();
session = jsch.getSession(username, host, 22);
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.setPassword(password);
session.connect();
// exec 'scp -f rfile' remotely
String command = "scp -f " + remoteFilename;
channel = session.openChannel("exec");
((ChannelExec) channel).setCommand(command);
// get I/O streams for remote scp
OutputStream out = channel.getOutputStream();
InputStream in = channel.getInputStream();
channel.connect();
byte[] buf = new byte[1024];
// send '\0'
buf[0] = 0;
out.write(buf, 0, 1);
out.flush();
while (true) {
int c = checkAck(in);
if (c != 'C') {
break;
}
// read '0644 '
in.read(buf, 0, 5);
long filesize = 0L;
while (true) {
if (in.read(buf, 0, 1) < 0) {
// error
break;
}
if (buf[0] == ' ') {
break;
}
filesize = filesize * 10L + (long) (buf[0] - '0');
}
String file = null;
for (int i = 0;; i++) {
in.read(buf, i, 1);
if (buf[i] == (byte) 0x0a) {
file = new String(buf, 0, i);
break;
}
}
// send '\0'
buf[0] = 0;
out.write(buf, 0, 1);
out.flush();
// read a content of lfile
FileOutputStream fos = null;
fos = new FileOutputStream(localFilename);
int foo;
while (true) {
if (buf.length < filesize) {
foo = buf.length;
} else {
foo = (int) filesize;
}
foo = in.read(buf, 0, foo);
if (foo < 0) {
// error
break;
}
fos.write(buf, 0, foo);
filesize -= foo;
if (filesize == 0L) {
break;
}
}
fos.close();
fos = null;
if (checkAck(in) != 0) {
System.exit(0);
}
// send '\0'
buf[0] = 0;
out.write(buf, 0, 1);
out.flush();
channel.disconnect();
session.disconnect();
}
} catch (JSchException jsche) {
System.err.println(jsche.getLocalizedMessage());
} catch (IOException ioe) {
System.err.println(ioe.getLocalizedMessage());
} finally {
channel.disconnect();
session.disconnect();
}
}
我刚刚发现sshj,它似乎比JSCH简洁得多(但它需要Java 6)。此时,文档主要是通过仓库中的示例进行的,通常这足以让我在其他地方查找内容,但对于我刚刚开始的项目来说,这似乎已经足够了。
看一看最近发布的SSHD,它基于Apache MINA项目。
github上有一个Jsch的全新版本:https : //github.com/vngx/vngx-jsch一些改进包括:全面的Javadoc,增强的性能,改进的异常处理和更好的RFC规范遵循性。如果您希望以任何方式做出贡献,请打开一个问题或发送请求请求。
我选择了miku的答案和jsch示例代码。然后,我不得不在会话期间下载多个文件并保留原始时间戳。这是我的示例代码如何执行此操作,可能很多人认为它很有用。请忽略filenameHack()函数本身的用例。
package examples;
import com.jcraft.jsch.*;
import java.io.*;
import java.util.*;
public class ScpFrom2 {
public static void main(String[] args) throws Exception {
Map<String,String> params = parseParams(args);
if (params.isEmpty()) {
System.err.println("usage: java ScpFrom2 "
+ " user=myid password=mypwd"
+ " host=myhost.com port=22"
+ " encoding=<ISO-8859-1,UTF-8,...>"
+ " \"remotefile1=/some/file.png\""
+ " \"localfile1=file.png\""
+ " \"remotefile2=/other/file.txt\""
+ " \"localfile2=file.txt\""
);
return;
}
// default values
if (params.get("port") == null)
params.put("port", "22");
if (params.get("encoding") == null)
params.put("encoding", "ISO-8859-1"); //"UTF-8"
Session session = null;
try {
JSch jsch=new JSch();
session=jsch.getSession(
params.get("user"), // myuserid
params.get("host"), // my.server.com
Integer.parseInt(params.get("port")) // 22
);
session.setPassword( params.get("password") );
session.setConfig("StrictHostKeyChecking", "no"); // do not prompt for server signature
session.connect();
// this is exec command and string reply encoding
String encoding = params.get("encoding");
int fileIdx=0;
while(true) {
fileIdx++;
String remoteFile = params.get("remotefile"+fileIdx);
String localFile = params.get("localfile"+fileIdx);
if (remoteFile == null || remoteFile.equals("")
|| localFile == null || localFile.equals("") )
break;
remoteFile = filenameHack(remoteFile);
localFile = filenameHack(localFile);
try {
downloadFile(session, remoteFile, localFile, encoding);
} catch (Exception ex) {
ex.printStackTrace();
}
}
} catch(Exception ex) {
ex.printStackTrace();
} finally {
try{ session.disconnect(); } catch(Exception ex){}
}
}
private static void downloadFile(Session session,
String remoteFile, String localFile, String encoding) throws Exception {
// send exec command: scp -p -f "/some/file.png"
// -p = read file timestamps
// -f = From remote to local
String command = String.format("scp -p -f \"%s\"", remoteFile);
System.console().printf("send command: %s%n", command);
Channel channel=session.openChannel("exec");
((ChannelExec)channel).setCommand(command.getBytes(encoding));
// get I/O streams for remote scp
byte[] buf=new byte[32*1024];
OutputStream out=channel.getOutputStream();
InputStream in=channel.getInputStream();
channel.connect();
buf[0]=0; out.write(buf, 0, 1); out.flush(); // send '\0'
// reply: T<mtime> 0 <atime> 0\n
// times are in seconds, since 1970-01-01 00:00:00 UTC
int c=checkAck(in);
if(c!='T')
throw new IOException("Invalid timestamp reply from server");
long tsModified = -1; // millis
for(int idx=0; ; idx++){
in.read(buf, idx, 1);
if(tsModified < 0 && buf[idx]==' ') {
tsModified = Long.parseLong(new String(buf, 0, idx))*1000;
} else if(buf[idx]=='\n') {
break;
}
}
buf[0]=0; out.write(buf, 0, 1); out.flush(); // send '\0'
// reply: C0644 <binary length> <filename>\n
// length is given as a text "621873" bytes
c=checkAck(in);
if(c!='C')
throw new IOException("Invalid filename reply from server");
in.read(buf, 0, 5); // read '0644 ' bytes
long filesize=-1;
for(int idx=0; ; idx++){
in.read(buf, idx, 1);
if(buf[idx]==' ') {
filesize = Long.parseLong(new String(buf, 0, idx));
break;
}
}
// read remote filename
String origFilename=null;
for(int idx=0; ; idx++){
in.read(buf, idx, 1);
if(buf[idx]=='\n') {
origFilename=new String(buf, 0, idx, encoding); // UTF-8, ISO-8859-1
break;
}
}
System.console().printf("size=%d, modified=%d, filename=%s%n"
, filesize, tsModified, origFilename);
buf[0]=0; out.write(buf, 0, 1); out.flush(); // send '\0'
// read binary data, write to local file
FileOutputStream fos = null;
try {
File file = new File(localFile);
fos = new FileOutputStream(file);
while(filesize > 0) {
int read = Math.min(buf.length, (int)filesize);
read=in.read(buf, 0, read);
if(read < 0)
throw new IOException("Reading data failed");
fos.write(buf, 0, read);
filesize -= read;
}
fos.close(); // we must close file before updating timestamp
fos = null;
if (tsModified > 0)
file.setLastModified(tsModified);
} finally {
try{ if (fos!=null) fos.close(); } catch(Exception ex){}
}
if(checkAck(in) != 0)
return;
buf[0]=0; out.write(buf, 0, 1); out.flush(); // send '\0'
System.out.println("Binary data read");
}
private static int checkAck(InputStream in) throws IOException {
// b may be 0 for success
// 1 for error,
// 2 for fatal error,
// -1
int b=in.read();
if(b==0) return b;
else if(b==-1) return b;
if(b==1 || b==2) {
StringBuilder sb=new StringBuilder();
int c;
do {
c=in.read();
sb.append((char)c);
} while(c!='\n');
throw new IOException(sb.toString());
}
return b;
}
/**
* Parse key=value pairs to hashmap.
* @param args
* @return
*/
private static Map<String,String> parseParams(String[] args) throws Exception {
Map<String,String> params = new HashMap<String,String>();
for(String keyval : args) {
int idx = keyval.indexOf('=');
params.put(
keyval.substring(0, idx),
keyval.substring(idx+1)
);
}
return params;
}
private static String filenameHack(String filename) {
// It's difficult reliably pass unicode input parameters
// from Java dos command line.
// This dirty hack is my very own test use case.
if (filename.contains("${filename1}"))
filename = filename.replace("${filename1}", "Korilla ABC ÅÄÖ.txt");
else if (filename.contains("${filename2}"))
filename = filename.replace("${filename2}", "test2 ABC ÅÄÖ.txt");
return filename;
}
}
http://code.google.com/p/connectbot/,在Windows linux或android上编译src \ com \ trilead \ ssh2,它可以创建本地端口转发器或创建动态端口转发器或其他