我正在编写一个Go程序,它将使用本机x/crypto/ssh库通过SSH连接到主机并删除一个交互式shell.
我正在使用RequestPty(),但远程端的(bash)shell与控制代码的行为不符合预期.
当我输入各种控制字符时,它们会被我的终端回复:
$ ^[[A
Run Code Online (Sandbox Code Playgroud)
角色仍然有效,如果按下向上箭头后按Enter键,则运行上一个命令 - 但控制字符输出会破坏应该在那里显示的内容.标签也是如此.
是否有一些直接的方法让这个工作?当我在过去实现类似的系统时,它不是一个问题,因为我刚刚讨论过openssh,并且进程组的语义将它排除在外.
我研究过" The TTY Demystified ",并且它还不清楚从哪里开始.
我想过要研究的几件事:
openssh 本身必须正确地完成这项工作,但它是一个真正最好的代码库来研究.
实际上我不清楚这个打印是由我的本地终端仿真器或shell还是由远程主机上的代码完成的.
我该从哪里开始?
以下是我的代码示例:
conf := ssh.ClientConfig{
User: myuser,
Auth: []ssh.AuthMethod{ssh.Password(my_password)}
}
conn, err := ssh.Dial("tcp", myhost, conf)
if err != nil {
return err
}
defer conn.Close()
session, err := conn.NewSession()
if err != nil {
return err
}
defer session.Close()
session.Stdout = os.Stdout
session.Stderr = os.Stderr
session.Stdin = os.Stdin
modes := ssh.TerminalModes{
ssh.ECHO: 0
ssh.TTY_OP_ISPEED: 14400,
ssh.TTY_OP_OSPEED: 14400
}
if err := session.RequestPty("xterm", 80, 40, modes); err != nil {
return err
}
if err = session.Shell(); err != nil {
return err
}
return session.Wait()
Run Code Online (Sandbox Code Playgroud)
我用以下的术语值尝试了这个xterm:screen-256color和vt100.
对于记录 - 在实际代码中,而不是仅仅调用session.Wait(),我有一个for/select循环捕获各种信号到进程并将它们发送到Session.
这些ssh.ECHO: 0和ssh.ECHOCTL: 0设置对我不起作用.对于遇到此问题的其他人,下面是使用Go ssh库获得完全可用的交互式终端所需的粗略代码:
config := return &ssh.ClientConfig{
User: "username",
Auth: []ssh.AuthMethod{ssh.Password("password")},
}
client, err := ssh.Dial("tcp", "12.34.56.78:22", config)
if err != nil { ... }
defer client.Close()
session, err := client.NewSession()
if err != nil { ... }
defer session.Close()
session.Stdout = os.Stdout
session.Stderr = os.Stderr
session.Stdin = os.Stdin
modes := ssh.TerminalModes{
ssh.ECHO: 1, // enable echoing
ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
}
fileDescriptor := int(os.Stdin.Fd())
if terminal.IsTerminal(fileDescriptor) {
originalState, err := terminal.MakeRaw(fileDescriptor)
if err != nil { ... }
defer terminal.Restore(fileDescriptor, originalState)
termWidth, termHeight, err := terminal.GetSize(fileDescriptor)
if err != nil { ... }
err = session.RequestPty("xterm-256color", termHeight, termWidth, modes)
if err != nil { ... }
}
err = session.Shell()
if err != nil { ... }
// You should now be connected via SSH with a fully-interactive terminal
// This call blocks until the user exits the session (e.g. via CTRL + D)
session.Wait()
Run Code Online (Sandbox Code Playgroud)
请注意,所有键盘功能(选项卡完成,向上箭头)和信号处理(CTRL + C,CTRL + D)都可以正常使用上面的设置.
禁用ECHOCTL终端模式。
modes := ssh.TerminalModes{
ssh.ECHO: 0,
ssh.ECHOCTL: 0,
ssh.TTY_OP_ISPEED: 14400,
ssh.TTY_OP_OSPEED: 14400
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1647 次 |
| 最近记录: |