我正在编写一个应用程序来管理多个设备之间的连接,但是当启动新连接时,即使在新的 goroutine 中,网络连接接口似乎也会被覆盖。
主应用程序在切片中创建设备,并在启动时调用以下命令(通信通道存储在相同的结构中,以便将来参考):
for _, device := range devices {
fmt.Printf("Starting device at %v\n", device.ipAddress)
go device.run(device.outboundChannel, device.inboundChannel)
success := <-device.outboundChannel
if success.section == 0 && success.value == true {
fmt.Printf("Device at %v started successfully!\n", device.ipAddress)
}
}
在内部,每个例程运行以下内容:
func (a *ani22) run(outComms chan<- aniCommand, inComms <-chan aniCommand) {
initErr := a.init()
if initErr != nil {
outComms <- aniCommand{3, 0, false, false, initErr.Error()}
}
outComms <- aniCommand{0, 0, true, true, "Connected!"}
fmt.Printf("Device at %v now monitoring!\n", a.ipAddress)
for {
// Application loop happens here
}
}
func (a *ani22) init() error {
if a.connection != nil {
return errors.New(fmt.Sprintf("Cannot connect to %v as connection already esablished!\n", a.ipAddress))
}
if a.ipAddress == "" {
return errors.New("No IP Address specified!")
}
timeout := 5 * time.Second
fmt.Printf("Dialling IP %v\n", a.ipAddress)
dialErr := errors.New("")
a.connection, dialErr = net.DialTimeout("tcp", a.ipAddress, timeout)
if dialErr != nil {
return dialErr
}
return nil
}
当在切片中使用单个设备运行时,它可以正常工作,但是当添加任何其他设备时,它会在一次成功连接后阻塞,几乎就像下一个设备的连接被覆盖一样,尽管它位于单独的 goroutine 中。
TLDR - 我没有正确检查所有我的比赛条件。
由于我实例化设备数组的方式,我似乎遇到了错误。
该数组是从导入的 CSV 文件生成的(为了清楚起见,省略了样板文件)。原始代码的工作原理如下:
type ani22 struct {
ipAddress string
connection net.Conn
chan1Led bool
chan2Led bool
inboundChannel chan aniCommand
outboundChannel chan aniCommand
}
func import () ([]ani22, map[int]ani22Channel, error) {
var aniList []ani22 // Blank array to hold devices
deviceMap := make(map[int]ani22Channel)
for line := range lines {
var tempAni ani22 // Make a temporary device, then fill in the details
tempAni.ipAddress = lines[line][0] + ":2202"
chan1Id, _ := strconv.Atoi(lines[line][1])
tempChannel := deviceMap[chan1Id]
if tempChannel.ipAddress != "" {
continue
} else {
tempChannel.ipAddress = tempAni.ipAddress
tempChannel.port = 1
deviceMap[chan1Id] = tempChannel
}
chan2Id, _ := strconv.Atoi(lines[line][2])
tempChannel = deviceMap[chan2Id]
if tempChannel.ipAddress != "" {
continue
} else {
tempChannel.ipAddress = tempAni.ipAddress
tempChannel.port = 2
deviceMap[chan2Id] = tempChannel
}
tempAni.outboundChannel = make(chan aniCommand)
tempAni.inboundChannel = make(chan aniCommand)
aniList = append(aniList, tempAni)
}
return aniList, deviceMap, nil
}
此代码不会激活类型中的 net.Conn 项,该项在 goroutine 脱离时调用的 a.init() 函数中处理:
func (a *ani22) init() error {
if a.connection != nil {
return errors.New(fmt.Sprintf("Cannot connect to %v as connection already esablished!\n", a.ipAddress))
}
if a.ipAddress == "" {
return errors.New("No IP Address specified!")
}
timeout := 5 * time.Second
fmt.Printf("Dialling IP %v\n", a.ipAddress)
dialErr := errors.New("")
a.connection, dialErr = net.DialTimeout("tcp", a.ipAddress, timeout)
if dialErr != nil {
return dialErr
}
return nil
}
当项目附加到数组时,看起来好像 net.Conn 对象/接口被默认分配。似乎已经解决了这个问题的新方法:
func import () ([]ani22, map[int]ani22Channel, error) {
var aniList []ani22
deviceMap := make(map[int]ani22Channel)
for line := range lines {
var tempAni ani22
tempAni.ipAddress = lines[line][0] + ":2202"
chan1Id, _ := strconv.Atoi(lines[line][1])
tempChannel := deviceMap[chan1Id]
if tempChannel.ipAddress != "" {
continue
} else {
tempChannel.ipAddress = tempAni.ipAddress
tempChannel.port = 1
deviceMap[chan1Id] = tempChannel
}
chan2Id, _ := strconv.Atoi(lines[line][2])
tempChannel = deviceMap[chan2Id]
if tempChannel.ipAddress != "" {
continue
} else {
tempChannel.ipAddress = tempAni.ipAddress
tempChannel.port = 2
deviceMap[chan2Id] = tempChannel
}
tempAni.outboundChannel = make(chan aniCommand)
tempAni.inboundChannel = make(chan aniCommand)
// Additional code relocated from main function, starting connection and routine before returning the array
fmt.Printf("Starting device at %v\n", tempAni.ipAddress)
go tempAni.run(tempAni.outboundChannel, tempAni.inboundChannel)
success := <-tempAni.outboundChannel
if success.section == 0 && success.value == true {
fmt.Printf("Device at %v started successfully!\n", tempAni.ipAddress)
}
aniList = append(aniList, tempAni)
}
return aniList, deviceMap, nil
}
我认为,通过在移动连接之前确保连接处于活动状态,我们可以确保它是唯一的,而不是让编译器决定处理“未使用”的变量。