Golang连接websocket和ssh服务端

依赖包:

go get github.com/gorilla/websocket
go get golang.org/x/crypto/ssh

主要步骤及注释:

// 定义授权方法
auth := make([]ssh.AuthMethod, 0)
// 使用密码认证
auth = append(auth, ssh.Password("用户密码"))
// 使用私钥认证
// key, _ := ssh.ParsePrivateKey([]byte("私钥内容"))
// auth = append(auth, ssh.PublicKeys(key))

// 客户端配置
clientConfig := &ssh.ClientConfig{
	User:    "root",  // 用户名
	Auth:    auth,  // 授权方法
	// 检查主机密钥的回调函数,这里设置为接受任何主机密钥
	HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}

// 连接ssh服务
if client, err := ssh.Dial("tcp", "IP地址:22", clientConfig); err != nil {
	return nil, err
}
defer client.Close()

// 新建会话
session, err := client.NewSession()
if err != nil {
	return nil, err
}
defer session.Close()

// 创建ssh通道
channel, inRequests, err := client.OpenChannel("session", nil)
if err != nil {
	return nil, err
}

// 终端模式
modes := ssh.TerminalModes{
	ssh.ECHO:          1,
	ssh.TTY_OP_ISPEED: 14400,
	ssh.TTY_OP_OSPEED: 14400,
}

// 存入数组
var modeList []byte
for k, v := range modes {
	kv := struct {
		Key byte
		Val uint32
	}{k, v}
	modeList = append(modeList, ssh.Marshal(&kv)...)
}
modeList = append(modeList, 0)

// 默认终端行和列数
const defaultCols = 150
const defaultRows = 35

// 定义pty请求消息体
req := PtyRequestMsg{
	Term:     "xterm",
	Columns:  defaultCols,
	Rows:     defaultRows,
	Width:    uint32(defaultCols * 8),
	Height:   uint32(defaultRows * 8),
	Modelist: string(modeList),
}
// 请求一个标准输出的终端
ok, err := channel.SendRequest("pty-req", true, ssh.Marshal(&req))
if !ok || err != nil {
	logrus.Error(err)
	return nil, err
}
// 开启用户的默认shell
ok, err = channel.SendRequest("shell", true, nil)
if !ok || err != nil {
	logrus.Error(err)
	return nil, err
}

// 从websocket读取用户输入
for {
	// p为输入内容
	_, p, err := ws.ReadMessage()
	if err != nil {
		return
	}
	// 写入到ssh通道
	_, err = channel.Write(p)
	if err != nil && err.Error() != io.EOF.Error() {
		return
	}
}

br := bufio.NewReader(channel)
buf := []byte{}
t := time.NewTimer(time.Microsecond * 100)
defer t.Stop()

// 创建一个go通道r, 一边接收ssh服务端数据, 一边发送数据给websocket
r := make(chan rune)

go func() {
	for {
		// 读取ssh通道的数据
		x, size, err := br.ReadRune()
		if err != nil {
			return
		}
		// 传给通道r
		if size > 0 {
			r <- x
		}
	}
}()

for {
	select {
	case d := <-r:
		// 读取数据到buf
		if d != utf8.RuneError {
			p := make([]byte, utf8.RuneLen(d))
			utf8.EncodeRune(p, d)
			buf = append(buf, p...)
		} else {
			buf = append(buf, []byte("@")...)
		}
	case <-t.C:
		// 每隔100微秒将数据发给websocket
		if len(buf) != 0 {
			err := ws.WriteMessage(websocket.TextMessage, buf)
			if err != nil {
				return
			}
			// 重置buf
			buf = []byte{}
		}
		// 重置时间
		t.Reset(time.Microsecond * 100)
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值