用于Java的SSH库

用于Java的SSH库,java,ssh,ssh-tunnel,Java,Ssh,Ssh Tunnel,有没有人有使用Java的SSH库连接的例子。这是一个非常流行的库,由maven、ant和eclipse使用。它是开源的,具有BSD风格的许可证。看看最近发布的,它基于Apache MINA项目。更新:GSOC项目和那里的代码没有激活,但这是: hierynomus自2015年初开始担任维护者。以下是旧的、不再维护的Github链接: 有一个GSOC项目: 代码质量似乎比JSch好,JSch虽然是一个完整的、有效的实现,但缺乏文档。Project page发布了一个即将发布的测试版,最后一

有没有人有使用Java的SSH库连接的例子。

这是一个非常流行的库,由maven、ant和eclipse使用。它是开源的,具有BSD风格的许可证。

看看最近发布的,它基于Apache MINA项目。

更新:GSOC项目和那里的代码没有激活,但这是:

hierynomus自2015年初开始担任维护者。以下是旧的、不再维护的Github链接:


有一个GSOC项目:

代码质量似乎比JSch好,JSch虽然是一个完整的、有效的实现,但缺乏文档。Project page发布了一个即将发布的测试版,最后一次提交到存储库是在8月中旬

比较API:

Session=null;
通道=空;
试一试{
JSch JSch=新的JSch();
session=jsch.getSession(用户名,主机,22);
java.util.Properties config=new java.util.Properties();
配置放置(“检查”、“否”);
session.setConfig(config);
session.setPassword(密码);
session.connect();
//远程执行“scp-f文件”
String command=“scp-f”+remoteFilename;
channel=session.openChannel(“exec”);
((ChannelExec)channel).setCommand(command);
//获取远程scp的I/O流
OutputStream out=channel.getOutputStream();
InputStream in=channel.getInputStream();
channel.connect();
字节[]buf=新字节[1024];
//发送“\0”
buf[0]=0;
out.write(buf,0,1);
out.flush();
while(true){
int c=签入(in);
如果(c!=“c”){
打破
}
//读‘0644’
in.read(buf,0,5);
长文件大小=0L;
while(true){
if(in.read(buf,0,1)<0){
//错误
打破
}
如果(buf[0]=''){
打破
}
filesize=filesize*10L+(长)(buf[0]-“0”);
}
字符串文件=null;
对于(int i=0;i++){
in.read(buf,i,1);
if(buf[i]==(字节)0x0a){
file=新字符串(buf,0,i);
打破
}
}
//发送“\0”
buf[0]=0;
out.write(buf,0,1);
out.flush();
//阅读lfile的内容
FileOutputStream=null;
fos=新文件输出流(localFilename);
int foo;
while(true){
if(buf.length<文件大小){
foo=buf.长度;
}否则{
foo=(int)文件大小;
}
foo=in.read(buf,0,foo);
如果(foo<0){
//错误
打破
}
fos.write(buf,0,foo);
filesize-=foo;
如果(文件大小==0L){
打破
}
}
fos.close();
fos=null;
如果(检查确认(in)!=0){
系统出口(0);
}
//发送“\0”
buf[0]=0;
out.write(buf,0,1);
out.flush();
通道断开();
session.disconnect();
}
}捕获(JSCHEException jsche){
System.err.println(jsche.getLocalizedMessage());
}捕获(ioe异常ioe){
System.err.println(ioe.getLocalizedMessage());
}最后{
通道断开();
session.disconnect();
}
}

我刚刚发现,它的API似乎比JSCH简洁得多(但它需要Java 6)。目前,文档主要是通过repo中的示例来编写的,通常这就足够让我去别处看看了,但对于我刚刚开始的一个项目来说,这似乎已经足够好了。

github上有一个全新版本的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;
    }

}
包示例;
导入com.jcraft.jsch.*;
导入java.io.*;
导入java.util.*;
公共类ScpFrom2{
公共静态void main(字符串[]args)引发异常{
Map params=parseParams(args);
if(params.isEmpty()){
System.err.println(“用法:Javascpfrom2”
+“user=myid password=mypwd”
+“主机=myhost.com端口=22”
+“编码=”
+“\“remotefile1=/some/file.png”
+“\“localfile1=file.png”
+“\“remotefile2=/other/file.txt”
+“\“localfile2=file.txt”
);
返回;
}
//默认值
if(params.get(“端口”)==null)
参数put(“端口”,“22”);
if(params.get(“encoding”)==null)
参数put(“编码”、“ISO-8859-1”);/“UTF-8”
会话=空;
试一试{
JSch JSch=新的JSch();
session=jsch.getSession(
params.get(“用户”),//myuserid
params.get(“主机”),//my.server.com
Integer.parseInt(params.get(“port”)//22
);
session.setPassword(params.get(“password”);
session.setConfig(“StrictHostKeyChecking”,“no”);//不提示输入服务器签名
session.connect();
//这是exec命令和字符串应答编码
字符串编码=params.get(“编码”);
int fileIdx=0;
while(true){
fileIdx++;
字符串remoteFile=params.get(“remoteFile”+fileIdx);
字符串localFile=params.get(“localFile”+fileIdx);
if(remoteFile==null | | remoteFile.equals(“”)
||localFile==null | | localFile.equals(“”)
打破
remoteFile=filenameHack(remoteFile);
localFile=filenameHa
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();
}

}
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;
    }

}