SCP使用-t标志的问题(“-stalling-”)

4
我正在开发一个Java应用程序,需要将一个特定的文件SCP到远程计算机。我使用了Jsch库,并按照网站上的ScpTo.java示例做了操作(链接:http://www.jcraft.com/jsch/examples/ScpTo.java)。
然而,在应用程序中,SCP命令会出现问题。因此,我尝试在Cygwin终端中手动运行SCP命令。
我的命令看起来像这样:
    scp -t /home/user/test.csv
    C0644 197171 C:\Users\user\Documents\test.csv

命令的输出内容为:
C:\Users\user\Documents\test.csv                0%    0     0.0KB/s - stalled -

看起来它好像只是这么做了。现在我认为这可能是防火墙问题,因此我尝试了几台其他远程机器,它们仍然给了我相同的问题。

有任何处理这种问题的想法吗?

非常感谢,

Joe

编辑:以下是Java代码:

import java.awt.Container;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UIKeyboardInteractive;
import com.jcraft.jsch.UserInfo;

class HPCConnector
{
    private static String username = "username";
    private static String host = "host.edu";

    JSch jsch;
    Session session;
    UserInfo ui;

    public HPCConnector() throws JSchException
    {
        jsch = new JSch();
        session = jsch.getSession(username, host, 22);
        ui = new HPCUserInfo();
        session.setUserInfo(ui);
    }

    public boolean validateConnection() 
    {
        boolean status = true;
        try {
            session.connect();
            if (status)
                return status;
            } catch (JSchException e) {
                e.printStackTrace();
                status = false;
            }
        return status;
    }

    public static class HPCUserInfo implements UserInfo, UIKeyboardInteractive
    {
        public String getPassword(){ return passwd; }
        public boolean promptYesNo(String str)
        {
          Object[] options={ "Yes", "No" };
          int foo=JOptionPane.showOptionDialog(null, str,"Warning", JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,null, options, options[0]);
           return foo==0;
        }

        String passwd;
        JTextField passwordField=(JTextField)new JPasswordField(20);

        public String getPassphrase(){ return null; }
        public boolean promptPassphrase(String message){ return true; }
        public boolean promptPassword(String message)
        {
          Object[] ob={passwordField}; 
          int result=
          JOptionPane.showConfirmDialog(null, ob, message,
                        JOptionPane.OK_CANCEL_OPTION);
          if(result==JOptionPane.OK_OPTION)
          {
              passwd=passwordField.getText();
              return true;
          }
          else{ return false; }
        }
        public void showMessage(String message)
        {
          JOptionPane.showMessageDialog(null, message);
        }
        final GridBagConstraints gbc = new GridBagConstraints(0,0,1,1,1,1,GridBagConstraints.NORTHWEST,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0);
        private Container panel;
        public String[] promptKeyboardInteractive(String destination,String name,String instruction,String[] prompt,boolean[] echo)
        {
          panel = new JPanel();
          panel.setLayout(new GridBagLayout());

          gbc.weightx = 1.0;
          gbc.gridwidth = GridBagConstraints.REMAINDER;
          gbc.gridx = 0;
          panel.add(new JLabel(instruction), gbc);
          gbc.gridy++;

          gbc.gridwidth = GridBagConstraints.RELATIVE;

          JTextField[] texts=new JTextField[prompt.length];
          for(int i=0; i<prompt.length; i++)
          {
            gbc.fill = GridBagConstraints.NONE;
            gbc.gridx = 0;
            gbc.weightx = 1;
            panel.add(new JLabel(prompt[i]),gbc);

            gbc.gridx = 1;
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.weighty = 1;
            if(echo[i])
            {
              texts[i]=new JTextField(20);
            }
            else
            {
              texts[i]=new JPasswordField(20);
            }
            panel.add(texts[i], gbc);
            gbc.gridy++;
          }

          if(JOptionPane.showConfirmDialog(null, panel, destination+": "+name,JOptionPane.OK_CANCEL_OPTION,JOptionPane.QUESTION_MESSAGE) ==JOptionPane.OK_OPTION)
          {
            String[] response=new String[prompt.length];
            for(int i=0; i<prompt.length; i++)
            {
              response[i]=texts[i].getText();
            }
            return response;
          }
          else
          {
            return null;  // cancel
          }
        }
     }

    public void transferToHPC(File spreadsheet) throws JSchException
    {
        OutputStream out = null;
        InputStream in = null;
        String command = "scp -t /home/user/" + spreadsheet.getName();
        Channel channel = session.openChannel("exec");
        ((ChannelExec)channel).setCommand(command);
        try{
            out = channel.getOutputStream();
            in = channel.getInputStream();
        } catch (IOException ex) {
            ex.printStackTrace();
        }

        System.out.println(command);
        long fileSize=  spreadsheet.length();

        channel.connect();

        command = "C0644 " + fileSize + " " + spreadsheet.getAbsolutePath() + "\n";
        try {
            if(checkAck(in)!=0){
                System.exit(0);
              }
            out.write(command.getBytes());
            out.flush();

            FileInputStream fis = new FileInputStream(spreadsheet);
            byte[] buffer = new byte[1024];

            while (true)
            {
                int length = fis.read(buffer, 0, buffer.length);
                if (length <= 0)
                    break;
                out.write(buffer, 0, 1);
            }
            fis.close();
            fis = null;
            System.out.println(command);

            buffer[0] = 0;
            out.write(buffer, 0, 1);
            out.flush();

            out.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        channel.disconnect();
        session.disconnect();
    }

      static int checkAck(InputStream in) throws IOException{
            int b=in.read();
            // b may be 0 for success,
            //          1 for error,
            //          2 for fatal error,
            //          -1
            if(b==0) return b;
            if(b==-1) return b;

            if(b==1 || b==2){
              StringBuffer sb=new StringBuffer();
              int c;
              do {
            c=in.read();
            sb.append((char)c);
              }
              while(c!='\n');
              if(b==1){ // error
            System.out.print(sb.toString());
              }
              if(b==2){ // fatal error
            System.out.print(sb.toString());
              }
            }
            return b;
          }
}

编辑2:控制台上没有出现任何异常,而使我感到困扰的主要函数是transferToHPC(文件电子表格)

编辑3:好吧,最终我放弃了这个问题。能够使用JSch的Sftp类并且它的工作方式符合我的意图。

我做了更多的阅读并阅读了Kenster的答案,我认为我应该保留-t标志供scp内部处理 :)谢谢大家!


发布您的Java代码以获取帮助。如果运行Java代码时出现任何异常,请也一并发布。 - vkg
2个回答

6
我理解的是,您手动运行了scp -t命令并输入了C0644行,然后从中得到了stalling消息。这并不表示任何问题。 scp -t通常是一个scp传输的接收端,由另一个要发送文件到接收端的scp实例启动。发送scp实例启动接收器,发送C行,标记一个文件即将到来,然后发送文件的数据。
您所做的是手动交互地启动接收器,并向其发送C行,指示文件即将到来。之后,接收器期望读取文件数据。由于您没有发送任何文件数据,接收器最终打印出状态消息,表示传输已停滞。
唯一的问题是,人们通常不会直接运行scp -t。在这种情况下,scp程序按预期工作。

我现在在我的 Mac 上看到我的 scp 无法移动,但是我在我的 bash 链中看不到任何输出的可能性(例如,如果我删除我的 bash 启动时的完整内容-没有 bash)。它在“scp -v -t。”上永久挂起,尝试从我的 Mac 复制文件到远程主机,我想知道为什么它要复制“。”特别是因为我指定了文件名。还有什么其他的问题吗?SSH 在两个方向上都正常工作,而 SCP 在将文件复制到 Mac 时也可以正常工作。 - clearlight

0

这个问题可能会在文件传输过程中尝试占用大带宽,但由于网络或防火墙问题而无法获取该带宽时发生。

尝试使用-l选项:scp -l x "file" "destination" 这里的x指定kb / sec。因此,如果将x的值设为256,则使用的带宽将为256kb / sec。


即使使用了-l标志,它仍然显示“- stalled -”,我还应该提到SCP对于常规语法运行良好:scp文件user@host.edu:/directory/file,正是这种特定的语法导致了停顿。 - joseph.liccini
“-t”选项是什么意思?我在这里找不到任何提及:http://www.openbsd.org/cgi-bin/man.cgi?query=scp&sektion=1 - Lokesh
1
这是scp协议中的“幕后”标志;据我所知,它将scp设置为“sink”模式,并将文件2的所有字节数据输入到文件1中。即scp -t file1 C0644 file2_size_in_bytes file2C中的C0644表示1个文件,而0644是该文件的模式。 - joseph.liccini

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接