Java için SSH kütüphanesi [kapalı]


190

Herkes Java SSH giriş için iyi bir kütüphane biliyor mu.


Trilead SSH kullanıyordum ama bugün siteyi kontrol ettiğimde vazgeçtikleri anlaşılıyor. :( Benim en sevdiğim oydu.
Peter D

1
BTW, Trilead SSH2'nin aktif olarak korunduğu görülüyor (Ekim 2013'te): [ github.com/jenkinsci/trilead-ssh2]
Mike Godin

Trilead SSH2'nin github.com/connectbot/sshlib adresinde bir çatalı var
user7610

Yanıtlar:


120

Java Kanal (JSch) Güvenli maven, karınca ve tutulma tarafından kullanılan, çok popüler bir kütüphanesidir. BSD tarzı lisanslı açık kaynak kodludur.


2
Kaynağı sourceforge.net/projects/jsch/files/jsch/jsch-0.1.42.zip/… adresinden indirmek ve "ant javadoc" komutunu çalıştırmak için kullanıyorsunuz
David Rabinowitz

73
Bir süre önce JSch kullanmayı denedim ve nasıl bu kadar popüler olduğunu anlayamıyorum. Kesinlikle hiçbir belge (kaynak içinde bile değil) ve korkunç bir API tasarımı ( techtavern.wordpress.com/2008/09/30/… oldukça iyi özetliyor) sunuyor
rluba

15
: Evet JSch bu iyidir, korkunç github.com/shikhar/sshj
anio

3
Genel yöntemler için javadoc ile bir JSch çeşidi: github.com/ePaul/jsch-documentation
user423430 19:30 '

4
stackoverflow.com/questions/2405885/any-good-jsch-examples/… komutları çalıştırmak ve çıktıyı almak için JSCH kullanımına bir örnek içerir.
Charity Leschinski

65

Güncelleme: GSOC projesi ve buradaki kod etkin değil, ancak bu: https://github.com/hierynomus/sshj

hierynomus 2015 başından beri sürdürücü olarak görev aldı. İşte daha eski, artık bakımsız olan Github bağlantısı:

https://github.com/shikhar/sshj


Bir GSOC projesi vardı:

http://code.google.com/p/commons-net-ssh/

Kod kalitesi, eksiksiz ve çalışan bir uygulama olsa da, dokümantasyona sahip olmayan JSch'den daha iyi görünüyor. Proje sayfası yaklaşan bir beta sürümüne dikkat çekiyor, depoya son taahhüt ağustos ortasıydı.

API'ları karşılaştırın:

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

http://www.jcraft.com/jsch/

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

}

2
Teşekkürler! Ben proje olarak bir kickstart verdi tohum olarak Apache SSHD kodu (zaman uyumsuz API sunuyor) kullandım.
shikhar

1
Harika. JSch kullanarak bir projeye başladım, ancak commons-net-ssh hakkında daha olumlu geri bildirimler duyarsam, geçiş yapmaktan gerçekten hoşlanıyorum.
miku

5
GSOC öğrencisi olduğumu söylemeliydim :)
shikhar

2
mutlu duyurmaktan github.com/shikhar/sshj - Eğer kavanoz en bulabilirsiniz orada, bir maven repo üzerine almak nasıl bulmaktan
Shikhar

1
jsch'in SFTP'si burada verilenlerden çok daha basittir. Belki de bu eski koddur, ancak kesinlikle modern API'nin bir örneği değildir.
Charles Duffy

24

Sadece JSCH'den çok daha özlü bir API'ye sahip gibi görünen sshj'yi keşfettim (ancak Java 6 gerektirir). Dokümantasyon çoğunlukla bu noktadaki repo örnekleri ile ve genellikle başka bir yere bakmam için yeterli, ancak yeni başladığım bir projeyi denemek için yeterince iyi görünüyor.


3
SSHJ aslında dış dünyadan biri tarafından uygulanabilir. JSCH, gizli ve büyük ölçüde anlaşılmaz bağımlılıkları olan kötü dokümantasyon ve API tasarımının bir karışıklığıdır. Neler olduğunu anlamaya çalışmak için kod boyunca yürümek için çok zaman harcamak istemiyorsanız, SSHJ kullanın. (Ve keşke JSCH hakkında sert veya çetrefilli olsaydım. Gerçekten de öyle.)
Robert Fischer

1
Evet, sshj. Denediğim her şey çalıştı: SCP, uzaktan işlem yürütme, yerel ve uzak port yönlendirme, jsch-agent-proxy ile ajan proxy'si . JSCH bir karışıklıktı.
Laurent Caillette

1
SSHJ ile ilgili sorun, çoklu komutları yürütmenin çok zor olmasıdır. SSHJ, komutları ateşle ve unut için harika olabilir, ancak daha karmaşık etkileşim programlamak istiyorsanız bu bir acıdır. (Yarım gün harcadım)
bvdb

18

Apache MINA projesine dayanan, son zamanlarda piyasaya sürülen SSHD'ye bir göz atın .


2
Bununla birlikte, bununla ilgili belgeler ve örnekler yoktur.
Andreas Mattisson

Belgelerin eksikliği hafifçe ortaya çıkıyor gibi görünüyor: /
Amalgovinus

5

Github'da Jsch'un yepyeni bir sürümü var: https://github.com/vngx/vngx-jsch Bazı iyileştirmeler şunları içerir: kapsamlı javadoc, gelişmiş performans, gelişmiş istisna yönetimi ve daha iyi RFC spesifikliği. Herhangi bir şekilde katkıda bulunmak isterseniz, lütfen bir sorun açın veya bir çekme isteği gönderin.


4
3 yıldan fazla bir süredir yeni bir taahhüt olmadı.
Mike Lowery

0

Miku'nun cevabını ve jsch örnek kodunu aldım. Daha sonra oturum sırasında birden fazla dosya indirmek ve orijinal zaman damgalarını korumak zorunda kaldım . Bu benim örnek kod nasıl, muhtemelen birçok kişi yararlı bulabilirsiniz. Lütfen filenameHack () işlevini kendi kullanım alanım yoksay.

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

}

Bir oturumu yeniden kullanabildiniz ve bağlantı kurma / bağlantıyı kesme yükünü önleyebildiniz mi?
Sridhar Sarnobat

0

http://code.google.com/p/connectbot/ , Windows linux veya android üzerinde src \ com \ trilead \ ssh2 derleyin, Yerel Bağlantı Noktası İletici oluşturabilir veya Dinamik Bağlantı Noktası İletici veya başka bir şey oluşturabilir

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.