- xml - AJAX/Jquery XML 解析
- 具有多重继承的 XML 模式
- .net - 枚举序列化 Json 与 XML
- XML 简单类型、简单内容、复杂类型、复杂内容
我进行了高低搜索,但我不确定我是否使用了错误的关键字,但我无法理解这一点。我正在构建一个应用程序,它接收主机名列表并通过 SSH 连接到这些主机名。它旨在维护这些连接(并在断开连接时重新连接)。定期地,我的程序将接受指令并向部分/所有这些主机执行命令。
我目前的问题是,我知道你不能初始化一个变量而不使用它,我必须为这些 SSH 连接动态创建变量,这样我就可以独立监控/管理它们(读/写,必要时重新连接等) .由于我对 go 的了解有限,而且倾向于不小心使事情过于复杂,到目前为止,我想到的最好的方法是使用一个结构并为每个连接及其参数(主机名、用户名、密码、SSH 配置详细信息、日志文件)附加位置等)。
目前我的狡猾代码看起来像这样:
package main
import (
"os"
"fmt"
"flag"
"golang.org/x/crypto/ssh"
"io"
"log"
"strings"
"time"
"encoding/xml"
"bufio"
"net"
)
// SSH connection struct
type SSHConnections struct {
Host string
User string
Password string
CLILogfile string
SSHConn ssh.Client
SSHConfig ssh.ClientConfig
}
func main() {
//parse list of addresses
var ipaddr = []string{"a.b.c.d","e.f.g.h"} //hard-coded for now
//build out SSHConnections struct
for i := 0; i < len(ipaddr); i++ {
tempsshConfig := &ssh.ClientConfig{
User: "administrator",
Auth: []ssh.AuthMethod{
ssh.Password("Password!"),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
tempsshConfig.Config.Ciphers = append(tempsshConfig.Config.Ciphers, "aes128-cbc")
var newitem = SSHConnections{
Host: ipaddr[i],
User: "administrator",
Password: "Password!",
CLILogfile: ipaddr[1],
SSHConn: ssh.Client,
SSHConfig: *tempsshConfig,
}
SSHConnections = append(SSHConnections, newitem)
}
使用上面的代码我得到了编译错误:
type ssh.Client is not an expression
type SSHConnections is not an expression
在此之后还有特定于连接的参数(日志文件声明、额外的 SSH 参数、实际的 SSH 连接过程)我将需要管理,大概在与上面相同的结构中。上面是我目前的绊脚石,我对如何解决这个问题一无所知,更不用说将下面的单连接代码集成到上面了。
//extra SSH parameters required before connecting
sshConfig.Config.Ciphers = append(sshConfig.Config.Ciphers, "aes128-cbc")
modes := ssh.TerminalModes{
ssh.ECHO: 0, // disable echoing
ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
}
//prepare logfiles
f, ferr := os.OpenFile("outputfile.txt", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
if ferr != nil {
panic(ferr)
}
defer f.Close()
//SSH connection procedure
connection, err := ssh.Dial("tcp", hostname+":22", sshConfig)
if err != nil {
log.Fatalf("Failed to dial: %s", err)
}
session, err := connection.NewSession()
handleError(err, true, "Failed to create session: %s")
sshOut, err := session.StdoutPipe()
handleError(err, true, "Unable to setup stdin for session: %v")
sshIn, err := session.StdinPipe()
handleError(err, true, "Unable to setup stdout for session: %v")
if err := session.RequestPty("xterm", 0, 200, modes); err != nil {
session.Close()
handleError(err, true, "request for pseudo terminal failed: %s")
}
if err := session.Shell(); err != nil {
session.Close()
handleError(err, true, "request for shell failed: %s")
}
为了使我的帖子更清晰,我删除了一大堆不相关的代码。我希望我在这方面取得了远程成功。
我什至不确定结构是否是我想要的,但接收可变数量的主机名的动态性以及单独控制它们的要求是关键。稍后,我可能还需要单独断开连接,因此我正在寻找可以操纵它们的结构。
非常感谢任何帮助我指明正确方向的人。谢谢!
------------- 在此行下方更新----------------
在 mu 的下面的帖子和一些谷歌搜索之后,我的代码现在看起来像这样(删除了导入):
var connections []SSHConnections
// SSH connection struct
type SSHConnections struct {
Host string
User string
Password string
CLILogfilepath string
CLILogfile *os.File
SSHConn *ssh.Client
Session *ssh.Session
SSHOut io.Reader
SSHIn io.WriteCloser
SSHConfig *ssh.ClientConfig
CLIReady string
SSHConnErr error
SessionErr error
SSHOutErr error
SSHInErr error
CLILogfileErr error
CommandQueue chan string
}
func handleError(e error, fatal bool, customMessage ...string) {
var errorMessage string
if e != nil {
if len(customMessage) > 0 {
errorMessage = strings.Join(customMessage, " ")
} else {
errorMessage = "%s"
}
if fatal == true {
log.Fatalf(errorMessage, e)
} else {
log.Print(errorMessage, e)
}
}
}
func writeToFile(f *os.File, err error, inputString string) {
if _, err = f.WriteString(inputString); err != nil {
panic(err)
}
}
func connectionWorker(i int) {
//this function is to monitor SSH connections and reconnect if/when they are terminated
fmt.Println("goroutine for: "+connections[i].Host)
for { //not sure if this is even necessary? yet to test
select {
case command := <-connections[i].CommandQueue:
fmt.Printf("received %v from queue\n", command)
default:
time.Sleep(1000 * time.Millisecond)
}
}
}
func main() {
//parse list of addresses
var ipaddr = []string{"host1","host2"}
//build out SSHConnections struct
for i := 0; i < len(ipaddr); i++ {
tempsshConfig := &ssh.ClientConfig{
User: "administrator",
Auth: []ssh.AuthMethod{
ssh.Password("Password!"),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
tempsshConfig.Config.Ciphers = append(tempsshConfig.Config.Ciphers, "aes128-cbc")
var newitem = SSHConnections{
Host: ipaddr[i],
User: "administrator",
Password: "Password!",
CLILogfilepath: ipaddr[i],
SSHConfig: tempsshConfig,
}
connections = append(connections, newitem)
}
modes := ssh.TerminalModes{
ssh.ECHO: 0, // disable echoing
ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
}
//establish connections, check each for relevant 'admin:' readiness
for i := 0; i < len(connections); i++ {
connections[i].SSHConn, connections[i].SSHConnErr = ssh.Dial("tcp", connections[i].Host+":22", connections[i].SSHConfig)
if connections[i].SSHConnErr != nil {
fmt.Println("Failed to dial: %s")
} else {
connections[i].Session, connections[i].SessionErr = connections[i].SSHConn.NewSession()
handleError(connections[i].SessionErr, true, "Failed to create session: %s")
connections[i].SSHOut, connections[i].SSHOutErr = connections[i].Session.StdoutPipe()
handleError(connections[i].SSHOutErr, true, "Unable to setup stdin for session: %v")
connections[i].SSHIn, connections[i].SSHInErr = connections[i].Session.StdinPipe()
handleError(connections[i].SSHInErr, true, "Unable to setup stdout for session: %v")
if err := connections[i].Session.RequestPty("xterm", 0, 200, modes); err != nil {
connections[i].Session.Close()
handleError(connections[i].SSHInErr, true, "request for pseudo terminal failed: %s")
}
}
if err := connections[i].Session.Shell(); err != nil {
connections[i].Session.Close()
handleError(err, true, "request for shell failed: %s")
}
//initialise the buffered CommandQueue channel
connections[i].CommandQueue = make(chan string, 1000)
//prepare logfiles
connections[i].CLILogfile, connections[i].CLILogfileErr = os.OpenFile(connections[i].CLILogfilepath+".txt", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
if connections[i].CLILogfileErr != nil {
panic(connections[i].CLILogfileErr)
}
defer connections[i].CLILogfile.Close()
writeToFile(connections[i].CLILogfile, connections[i].CLILogfileErr, "testing output to file\r\n")
//monitor/maintain connections, monitor work queue and execute
go connectionWorker(i)
}
}
以上内容并不漂亮也不完美,如果有人要复制/粘贴,可能还需要进行一些调整,所以请记住这一点。我敢肯定,通过适当的测试我会偶然发现很多错误,但目前它可以按预期工作。我原来的疑问现在都得到了解答,谢谢!
最佳答案
你的循环看起来像这样:
for i := 0; i < len(ipaddr); i++ {
// ...
var newitem = SSHConnections{
// ...
SSHConn: ssh.Client,
// ...
}
SSHConnections = append(SSHConnections, newitem)
}
当你构建 newitem
时,你没有 SSHConn
的 ssh.Client
所以你应该把它去掉(并且因此使用它的零值)而不是尝试使用 ssh.Client
类型作为表达式;这是你的第一个错误。
第二个错误是类似的:您使用的类型(在本例中为 SSHConnections
)您确实想要使用 slice :
SSHConnections = append(SSHConnections, newitem)
应该是:
someSlice = append(someSlice, newitem)
那个循环应该看起来更像这样:
var connections []SSHConnections
for i := 0; i < len(ipaddr); i++ {
// ...
var newitem = SSHConnections{
// Everything that's there now except the SSHConn ...
}
connections = append(connections, newitem)
}
或者,既然您知道连接
需要多大:
connections := make([]SSHConnections, len(ipaddr))
for i := 0; i < len(ipaddr); i++ {
// ...
var newitem = SSHConnections{
// Everything that's there now except the SSHConn ...
}
connections[i] = newitem
}
然后稍后您调用 ssh.Dial
和 connection.NewClient
来获取可能会在您的终端中的 ssh.Client
连接
。
此外,您最好为 SSHConn
和 SSConfig
使用指向 SSHConnections
的指针,因为这是包的接口(interface)想要使用的.
关于go - 初始化/管理并发 SSH 连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48455865/
我是 Spring 新手,这就是我想要做的事情: 我正在使用一个基于 Maven 的库,它有自己的 Spring 上下文和 Autowiring 字段。 它的bean配置文件是src/test/res
我在我的测试脚本中有以下列表初始化: newSequenceCore=["ls", "ns", "*", "cm", "*", "ov", "ov", "ov", "ov", "kd"] (代表要在控
这个问题在这里已经有了答案: 关闭 11 年前。 Possible Duplicate: Class construction with initial values 当我查看 http://en.
我得到了成员变量“objectCount”的限定错误。编译器还返回“ISO C++ 禁止非常量静态成员的类内初始化”。这是主类: #include #include "Tree.h" using n
我有如下所示的a.h class A { public: void doSomething()=0; }; 然后我有如下所示的b.h #include "a.h" class b: publi
我需要解析 Firebase DataSnapshot (一个 JSON 对象)转换成一个数据类,其属性包括 enum 和 list。所以我更喜欢通过传递 DataSnapshot 来手动解析它进入二
我使用 JQuery 一段时间了,我总是使用以下代码来初始化我的 javascript: $(document).ready( function() { // Initalisation logic
这里是 Objective-C 菜鸟。 为什么会这样: NSString *myString = [NSString alloc]; [myString initWithFormat:@"%f", s
我无法让核心数据支持的 NSArrayController 在我的代码中正常工作。下面是我的代码: pageArrayController = [[NSArrayController alloc] i
我对这一切都很陌生,并且无法将其安装到我的后端代码中。它去哪里?在我的页脚下面有我所有的 JS? 比如,这是什么意思: Popup initialization code should be exec
这可能是一个简单的问题,但是嘿,我是初学者。 所以我创建了一个程序来计算一些东西,它目前正在控制台中运行。我决定向其中添加一个用户界面,因此我使用 NetBeans IDE 中的内置功能创建了一个 J
我有 2 个 Controller ,TEST1Controller 和 TEST2Controller 在TEST2Controller中,我有一个initialize()函数设置属性值。 如果我尝
据我所知, dependentObservable 在声明时会进行计算。但如果某些值尚不存在怎么办? 例如: var viewModel ={}; var dependentObservable1 =
我正在阅读 POODR 这本书,它使用旧语法进行默认值初始化。我想用新语法实现相同的功能。 class Gear attr_reader :chainring, :cog, :wheel de
我按照 polymer 教程的说明进行操作: https://www.polymer-project.org/3.0/start/install-3-0 (我跳过了可选部分) 但是,在我执行命令“po
很抱歉问到一个非常新手的Kotlin问题,但是我正在努力理解与构造函数和初始化有关的一些东西。 我有这个类和构造函数: class TestCaseBuilder constructor(
假设我们有一个包含 30 列和 30 行的网格。 生命游戏规则简而言之: 一个小区有八个相邻小区 当一个细胞拥有三个存活的相邻细胞时,该细胞就会存活 如果一个细胞恰好有两个或三个活的相邻细胞,那么它就
我是 MQTT 和 Android 开放附件“AOA” 的新手。在阅读教程时,我意识到,在尝试写入 ByteArrayOutputStream 类型的变量之前,应该写入 0 或 0x00首先到该变量。
我有 2 个 Controller ,TEST1Controller 和 TEST2Controller 在TEST2Controller中,我有一个initialize()函数设置属性值。 如果我尝
我有一个inotify /内核问题。我正在使用“inotify” Python项目进行观察,但是,我的问题仍然是固有的关于inotify内核实现的核心。 Python inotify项目处理递归ino
我是一名优秀的程序员,十分优秀!