如果你需要网页版Xshell,那么你找对了就是这里
那么废话不说.直接粘贴代码如下:
vue前端代码如下,包自己下载.不会百度
注意:这里因为用的是xterm4版本.所以跟网上其他人不一样,其实并不用写websocket太多的代码.因为xterm4版本集成了.还有你需要知道原理:将前端输出的任何东西不加处理全部通过websocket传到后端,交给后端处理反馈回来.再说一遍:不要做任何处理
gin框架所以调用代码如下:(websocket 默认get请求调用即可)
router.GET("/ws", demo_service.DemoServiceApp.WS)
GO后端处理代码,不多说看注释就明白了
var upGrader = websocket.Upgrader{
ReadBufferSize: 2048,
WriteBufferSize: 2048,
CheckOrigin: func(r *http.Request) bool {
return true
},
}
type wsBufferWriter struct {
buffer bytes.Buffer
mu sync.Mutex
}
//wsBufferWriter接口实现
func (w *wsBufferWriter) Write(p []byte) (n int, err error) {
w.mu.Lock()
defer w.mu.Unlock()
return w.buffer.Write(p)
}
func (w *wsBufferWriter) Bytes() []byte {
w.mu.Lock()
defer w.mu.Unlock()
return w.buffer.Bytes()
}
func (w *wsBufferWriter) Reset() {
w.mu.Lock()
defer w.mu.Unlock()
w.buffer.Reset()
}
/**
网页版本xShell经典案例
环境:vue+xterm4.js+websocket+ssh(go)
原理: 网页版本xShell原理,前端以websocket技术为通讯平台,go后端生成xShell后端,
前端将输入的任何结果发送到后端,通通交给后端处理.这里我要强调三下,
前端不做任何处理! 前端不做任何处理! 前端不做任何处理!
直接将结果送到后端,因为如果前端做处理,会很复杂,shell有很多键要处理.
注意:这里只是演示教学,代码中的异常处理最好封装一下.
by lw on 二〇二二年三月五日 21:52:49
*/
func (s *DemoService) WS(context *gin.Context) {
fmt.Println("======ws入口====")
//1.升级连接,从http--->websocket
upGrade, err := upGrader.Upgrade(context.Writer, context.Request, nil)
if err != nil {
context.AbortWithStatus(http.StatusOK)
fmt.Println("http升级websocket失败")
return
}
defer upGrade.Close() //延迟关闭链接...
//2.连接ssh
config := ssh.ClientConfig{
Timeout: time.Second * 5,
User: "root",
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
Auth: []ssh.AuthMethod{ssh.Password("root")}, //如果有秘钥这里可以换秘钥,这里我写死root,演示案例而已.
}
//ssh拨号以tcp方式连接服务器
sshDial, err2 := ssh.Dial("tcp", "192.168.0.114:22", &config) //服务器配置地址
if err2 != nil {
upGrade.WriteMessage(websocket.TextMessage, []byte("\n第二步:ssh连接失败,详情:"+err2.Error()))
return
}
defer sshDial.Close()
//3.ssh 创建shell的session会话
session, err3 := sshDial.NewSession()
if err3 != nil {
upGrade.WriteMessage(websocket.TextMessage, []byte("\n第三步:ssh创建会话失败"+err3.Error()))
return
}
pipe, _ := session.StdinPipe()
wsBuffer := new(wsBufferWriter)
session.Stdout = wsBuffer
session.Stderr = wsBuffer
modes := ssh.TerminalModes{
ssh.ECHO: 1,
ssh.TTY_OP_ISPEED: 14400,
ssh.TTY_OP_OSPEED: 14400,
}
//伪造xterm终端
err = session.RequestPty("xterm", 100, 100, modes)
if err != nil {
upGrade.WriteMessage(websocket.TextMessage, []byte("第三步:会话伪造终端失败"+err.Error()))
return
}
err = session.Shell()
if err != nil {
upGrade.WriteMessage(websocket.TextMessage, []byte("第三步:启动shell终端失败"+err.Error()))
return
}
var demo = &DemoService{
stdinPipe: pipe,
comboOutput: wsBuffer,
session: session,
wsConn: upGrade,
}
//defer session.Close()
quitChan := make(chan bool, 3)
//4.以上初始化信息基本结束.下面是携程读写websocket和ssh管道的 *** 作.也就是信息通信
demo.start(quitChan)
//session 等待
go demo.Wait(quitChan)
<-quitChan
}
func (s *DemoService) start(quitChan chan bool) {
go s.receiveWsMsg(quitChan)
go s.sendWsOutput(quitChan)
}
//将客户端信息返回到
func (s *DemoService) sendWsOutput(quitChan chan bool) {
wsConn := s.wsConn
defer setQuit(quitChan)
ticker := time.NewTicker(time.Millisecond * time.Duration(60))
defer ticker.Stop()
for {
select {
case <-ticker.C:
if s.comboOutput == nil {
return
}
bytes := s.comboOutput.Bytes()
if len(bytes) > 0 {
wsConn.WriteMessage(websocket.TextMessage, bytes)
s.comboOutput.buffer.Reset()
}
case <-quitChan:
return
}
}
}
//读取ws信息写入ssh客户端中.
func (s *DemoService) receiveWsMsg(quitChan chan bool) {
wsConn := s.wsConn
defer setQuit(quitChan) //告诉其他携程退出
for {
select {
case <-quitChan:
return
default:
//1.websocket 读取信息
_, data, err := wsConn.ReadMessage()
fmt.Println("=========readMessae===", string(data))
if err != nil {
fmt.Println("receiveWsMsg=>读取ws信息失败", err)
return
}
//2.读取到的数据写入ssh 管道内.
s.stdinPipe.Write(data)
}
}
}
func (s *DemoService) Wait(quitChan chan bool) {
if err := s.session.Wait(); err != nil {
setQuit(quitChan)
}
}
func setQuit(quitChan chan bool) {
quitChan <- true
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)