【问题标题】:How to select network interface when connecting to SFTP with JSch使用 JSch 连接 SFTP 时如何选择网络接口
【发布时间】:2014-10-25 06:40:49
【问题描述】:

我在通过 JSch 创建与远程 SFTP 服务器的会话时遇到问题:

我通过shell连接sftp服务器的命令是:

sftp -o BindAddress=SOME_IP_ADDRRESS myUserName@HOST_IP_ADDR

它工作正常,但是当我尝试使用 Java (JSch) 时,我得到一个超时异常。 Java代码是

/* KEY_FILE_NAME = is a file with rsa public key */
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource(KEY_FILE_NAME).getFile());
JSch jsch = new JSch();
jsch.addIdentity(file.getAbsolutePath());
Properties hash = new Properties();
hash.put("StrictHostKeyChecking", "no");
logger.debug("SSh Server Host name >>" + SSH_SERVER_HOST_NAME + " || User Name >>" +  SSH_SERVER_USER_NAME);

session = jsch.getSession(SSH_SERVER_USER_NAME, SSH_SERVER_HOST_NAME);
UserInfo ui = new MyUserInfo();
session.setUserInfo(ui);
session.setConfig(hash);
session.setPort(22);
session.setTimeout(45000);
session.connect();

我得到的例外是:

com.jcraft.jsch.JSchException:超时:未建立套接字

我猜它即将到来,因为我没有设置 BindAddress-o 选项,而我在使用 shell 命令时正在使用该选项。如果是这种情况,那么如何在 JSch 中设置 -o BindAddress 参数?或者我做错了什么,请提出建议。

【问题讨论】:

    标签: java bind sftp jsch


    【解决方案1】:

    我认为 JSch 中没有明确支持选择要连接的网络接口。

    但是你可以实现一个SocketFactory接口,比如它使用constructor overload with the localAddr创建一个Socket实例:

    public Socket(InetAddress address, int port, InetAddress localAddr, int localPort)
    

    (使用 0 表示 localPort

    然后在调用connect()之前将工厂传递给Session.setSocketFactory(),你应该会很好。

    【讨论】:

    • 感谢您所做的一切。我正在尝试解决方案并将更新。
    【解决方案2】:

    我已经实现了解决方案,我在调用session.connect()之前添加了以下代码。

    session.setSocketFactory(new SocketFactory() 
    {
        InputStream in = null;
        OutputStream out = null;
    
        public InputStream getInputStream(Socket socket) throws IOException 
        {
            if (in == null)
                in = socket.getInputStream();
            return in;
        }
    
        public OutputStream getOutputStream(Socket socket) throws IOException 
        {
            if (out == null)
                out = socket.getOutputStream();
            return out;
        }
    
        public Socket createSocket(String host, int port) throws IOException, UnknownHostException 
        {
           // The IP Addresses are changed ....
           // using the original IP in my code
            byte[] remoteIpAddr = new byte[] { (byte) 11,(byte) 11, 11, 11 }; 
            byte[] localIpAddr = new byte[] { 55, 55, 55, 55 };
    
            InetAddress remoteIp = InetAddress.getByAddress(remoteIpAddr);
            InetAddress localIp = InetAddress.getByAddress(localIpAddr);
    
            logger.debug("remoteIp >>" + remoteIp.toString());
            logger.debug("localIp >>" + localIp.toString());
            Socket socket = new Socket(remoteIp, 22, localIp, 0);
            logger.debug("socket created >> " + socket.toString());
            return socket;
        }
    });
    

    及其创建套接字:检查日志文件中的 >>

    logger.debug("socket created >> " + socket.toString());
    

    但现在我遇到了一个例外:

    授权取消

    可能是什么原因,我的关键是一个 id_rsa.pub 文件,它以

    开头
    ssh-rsa AXTYU....
    

    我已经通过我在session.addIdentity()方法中使用的keygen从这个文件创建了私钥文件,私钥的格式是:

    -----BEGIN RSA PRIVATE KEY-----
    KIOPU.....
    -----END RSA PRIVATE KEY-----
    

    我错过了什么,请建议...

    【讨论】:

    • 感谢分享解决方案。不过,为新问题开始新问题。这是问答网站,不是论坛。
    • 请注意,您应该使用createSockethostport 参数,而不是将它们硬编码到方法实现中。
    • 嗨马丁:非常感谢您的帮助,现在我的代码工作正常.. 我犯的错误是我使用了错误的私钥文件。以前的代码工作正常。只需更改密钥内容并将私钥文件名从 id_rsa.pub 更改为 id_rsa。
    【解决方案3】:

    这将允许您绑定到特定地址(和端口,应该需要):

    class MySocketFactory implements SocketFactory {
    
        @Override
        public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
            Socket socket = new Socket();
            socket.bind(new InetSocketAddress("1.1.1.1", 0));
            socket.connect(new InetSocketAddress(host, port));
    
            return socket;
        }
    
        @Override
        public InputStream getInputStream(Socket socket) throws IOException {
            return socket.getInputStream();
        }
    
        @Override
        public OutputStream getOutputStream(Socket socket) throws IOException {
            return socket.getOutputStream();
        }
    
    }
    

    我在我的 Linux 机器上使用netstat -an 验证了这一点,并观察到连接的本地端绑定到具有临时端口号的 1.1.1.1(我暂时使用此地址设置了一个接口)。

    我在调用session.connect()之前立即设置了工厂:

    SocketFactory sfactory = new MySocketFactory();
    session.setSocketFactory(sfactory);
    
    session.connect();
    

    【讨论】:

      猜你喜欢
      • 2021-09-25
      • 2023-03-03
      • 1970-01-01
      • 2011-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-19
      相关资源
      最近更新 更多