golang怎么实现ssh


这篇文章主要介绍“golang怎么实现ssh”,在日常操作中,相信很多人在golang怎么实现ssh问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”golang怎么实现ssh”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!在日常的一些开发场景中,我们需要去和远程服务器进行免费云主机域名一些通信,执行一些相关命令操作,这个时候我们就可以使用SSH协议实现目标。SSH协议是建立在应用层上的安全协议,全称为Secure Shell,采用的是面向连接的TCP协议进行传输,也就意味着它是安全可靠的。需要注意的是文件传输并不能在SSH协议上完成,需要在下面提到的SFTP协议完成。Go官方为我们提供了用于实现SSH连接的package,位于golang.org/x/crypto下,通过在程序中调用包中提供的相关方法,便可以实现与其他机器进行通信。使用前我们需要使用go get导入相关的依赖包。

gogetgolang.org/x/crypto/ssh

在进行通信之前,我们还需要配置一些用于配置一些用于建立连接的相关参数。ssh包下的ClientConfig结构体中,定义了建立SSH连接需要用到的一些配置项,部分项提供了默认参数,我们使用时可以不进行声明。下面的代码段中,我们首先是声明了用户名和密码,连接超时时间设置为10秒钟,addr变量定义了目标机器的IP地址以及端口。HostKeyCallback项,我们设置了忽略,这是因为SSH协议为客户端提供了两种安全验证方式,一种是基于口令的安全验证,也就是我们常常使用的账号密码形式,另外一种则是基于密钥的安全验证,相较于第一种,这种形式的校验方法极大的提升了安全等级,缺点则是时间损耗相对较长。如果需要使用这种方式进行校验,首先我们需要在服务器上为自己创建一对密钥,作为客户端进行访问时,首先会向服务端发送安全验证请求,服务端收到请求后,首先会将机器上保存的公钥与客户端发送的公钥进行比较,如果一致,服务端则会向客户端响应加密质询,客户端接受到质询之后,使用私钥进行解密,然后再将解密结果发送给服务端,服务端进行校验后再返回响应结果,到这里就算是完成了一段密钥校验。

//添加配置
config:=&ssh.ClientConfig{
User:"root",
Auth:[]ssh.AuthMethod{ssh.Password("Password")},
HostKeyCallback:ssh.InsecureIgnoreHostKey(),
Timeout:10*time.Second,
}
}
addr:=fmt.Sprintf("%v:%v",IP,Port)

在完成了所有的参数初始化之后,我们便可以调用Dial方法建立SSH连接。Dial方法一共有三个参数和两个返回值,第一个参数network为网络类型,这里我们使用面向连接的TCP协议,第二个参数addr则为目标机器的IP地址和端口号,第三个参数config则为前面我们生命的配置项。Dial会返回一个SSH连接和错误类型。func Dial(network, addr string, config *ClientConfig) (*Client, error)

//建立SSH连接
sshClient,err:=ssh.Dial("tcp",addr,config)
iferr!=nil{
log.Fatal("unabletocreatesshconn")
}

在建立了与目标机器的SSH连接之后,我们就可以通过创建SSH会话来与目标机器进行通信。通过NewSession()方法便可以实现这一操作。

//建立SSH会话
sshSession,err:=sshClient.NewSession()iferr!=nil{
log.Fatal("unabletocreatesshsession")
}

与目标机器建立会话后,我们就可以通过执行命令等来操作远程服务器。Go目前为我们提供了五个用于操作远程机器的方法,分别是Run(), Start(), Output(), CombineOutpt(), Shell()。?其中 Output(), **CombineOutpt()**这两个方法是对Run()方法进行不同程度上的封装,校验了输出流,错误流等相关内容。

//Outputrunscmdontheremotehostandreturnsitsstandardoutput.
func(s*Session)Output(cmdstring)([]byte,error){ifs.Stdout!=nil{returnnil,errors.New("ssh:Stdoutalreadyset")
}varbbytes.Buffer
s.Stdout=&b
err:=s.Run(cmd)returnb.Bytes(),err
}

//CombinedOutputrunscmdontheremotehostandreturnsitscombined
//standardoutputandstandarderror.
func(s*Session)CombinedOutput(cmdstring)([]byte,error){ifs.Stdout!=nil{returnnil,errors.New("ssh:Stdoutalreadyset")
}ifs.Stderr!=nil{returnnil,errors.New("ssh:Stderralreadyset")
}varbsingleWriter
s.Stdout=&b
s.Stderr=&b
err:=s.Run(cmd)returnb.b.Bytes(),err
}

Run()方法则是对Start()方法进行了封装,添加了Wait方法,用于校验远程服务器的退出指令。Wait()方法中有一个管道类型的变量exitStatus,它是用来保存每次执行命令后,机器返回的退出状态的。有兴趣的朋友可以去看看这块的代码,这里就不贴代码了。这里面有一个坑,如果我们在远程机器上去运行一个永远不会停止的程序,这个时候我们的程序一直等待不到远程机器发送的退出指令,就会造成程序一直阻塞而无法正常返回。解决的办法是用一个协程去单独执行这一块的任务,或者是使用定时器来定时结束session会话,来正常返回。Start()方法与Shell方法一致,都是返回一个error类型,在底层都是调用了start()方法和SendRequest方法,关于这两个方法的内容这里就不做详细介绍了,有兴趣的朋友可以自行去阅读。唯一的区别是Start()方法有一个string类型的参数,用于接收用户输入的参数,而Shell()方法是无参数的。使用Shell()方法配合RequestPty()等方法可以在本地建立一个伪终端,可以直接通过输入命令的形式操作目标机器。下面都会做一个示例。

//Run
func(s*Session)Run(cmdstring)error{
err:=s.Start(cmd)iferr!=nil{
fmt.Println(err)returnerr
}returns.Wait()
}

//Startrunscmdontheremotehost.Typically,theremote
//serverpassescmdtotheshellforinterpretation.
//ASessiononlyacceptsonecalltoRun,StartorShell.
func(s*Session)Start(cmdstring)error{ifs.started{returnerrors.New("ssh:sessionalreadystarted")
}
req:=execMsg{
Command:cmd,
}

ok,err:=s.ch.SendRequest("exec",true,Marshal(&req))iferr==nil&&!ok{
err=fmt.Errorf("ssh:command%vfailed",cmd)
}iferr!=nil{returnerr
}returns.start()
}

这里我们使用Run()方法来演示一下如果去执行命令,其他方法类型就不做演示了。这里我们使用一个标准输出流、错误流来保存执行结果。这里演示了一个简单的执行过程,使用了cd命令到/home/min目录下,在给helloworld程序添加可执行权限,最后运行程序。

varstdoutBuf,stderrBufbytes.Buffer
session.Stdout=&stdoutBuf
session.Stderr=&stderrBuf
//cd/home/min
//chmod+xhelloworld
//./helloworld
cmd:=fmt.Sprintf("cd%v;chmod+x%v;%v&","/home/min","helloworld",./helloworld)
err:=session.Run(cmd)iferr!=nil{
log.Fatal("[ERROR]:",session.Stderr,err)
}

//设置TerminalMode
	modes:=ssh.TerminalModes{
		ssh.ECHO:0,//关闭回显
		ssh.TTY_OP_ISPEED:14400,//设置传输速率
		ssh.TTY_OP_OSPEED:14400,
	}
//请求伪终端
	err=session.RequestPty("linux",32,160,modes)	iferr!=nil{
		log.Println(err)		return
	}
//设置输入输出
	session.Stdout=os.Stdout
	session.Stdin=os.Stdin
	session.Stderr=os.Stderr

	session.Shell()//启动shell
	session.Wait()//等待退出

//机器平台信息typeMachinestruct{
IPstring
Portstring
Usernamestring
Passwordstring}//建立SSH连接funcCreateSSHConn(m*model.Machine)error{//初始化连接信息
config:=&ssh.ClientConfig{
User:m.Username,
Auth:[]ssh.AuthMethod{ssh.Password(m.Password)},
HostKeyCallback:ssh.InsecureIgnoreHostKey(),
Timeout:10*time.Second,
}
addr:=fmt.Sprintf("%v:%v",m.IP,m.Port)//建立ssh连接
sshClient,err:=ssh.Dial("tcp",addr,config)iferr!=nil{
fmt.Println("unablecreatesshconn",err)returnerr
}defersshClient.Close()
//建立ssh会话
session,err:=sshClient.NewSession()iferr!=nil{
fmt.Println("unablecreatesshconn",err)returnerr
}defersession.Close()

//执行命令
varstdoutBuf,stderrBufbytes.Buffer
session.Stdout=&stdoutBuf
session.Stderr=&stderrBuf

cmd:=fmt.Sprintf("cd%v;chmod+x%v;%v&","/home/min","helloworld",./helloworld)iferr:=session.Run(cmd);err!=nil{
log.Fatal("[ERROR]:",session.Stderr,err)
}
//创建伪终端
//设置TerminalMode
modes:=ssh.TerminalModes{
ssh.ECHO:0,//关闭回显
ssh.TTY_OP_ISPEED:14400,//设置传输速率
ssh.TTY_OP_OSPEED:14400,
}
//请求伪终端
err=session.RequestPty("linux",32,160,modes)iferr!=nil{
log.Fatal(err)
}
//设置输入输出
session.Stdout=os.Stdout
session.Stdin=os.Stdin
session.Stderr=os.Stderr

session.Shell()//启动shell
session.Wait()//等待退出

returnerr
}

到此,关于“golang怎么实现ssh”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注百云主机网站,小编会继续努力为大家带来更多实用的文章!

相关推荐: vue怎么获取一个类名

这篇文章主要介绍“vue怎么获取一个类名”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“vue怎么获取一个类名”文章能帮助大家解决问题。步骤如下:1.首先,在vue-cli中创建一个vue.js项目;2.vue.js项目…

免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。

Like (0)
Donate 微信扫一扫 微信扫一扫
Previous 02/20 18:25
Next 02/20 18:25

相关推荐