gpt4 book ai didi

multithreading - 无法连接时停止 channel

转载 作者:IT王子 更新时间:2023-10-29 01:27:23 26 4
gpt4 key购买 nike

我有以下代码可以正常工作,问题是当 socket.Connect() fails 连接时我想停止这个过程,我已经尝试使用以下代码但它不起作用,即如果套接字连接失败,程序仍然运行。我想要发生的是,如果 connect 失败,进程将停止 并且 channe ......我在这里错过了什么?

func run (appName string) (err error) {


done = make(chan bool)
defer close(done)


serviceURL, e := GetContext().getServiceURL(appName)

if e != nil {
err = errors.New("process failed" + err.Error())
LogDebug("Exiting %v func[err =%v]", methodName, err)
return err
}

url := "wss://" + serviceURL + route


socket := gowebsocket.New(url)
addPass(&socket, user, pass)


socket.OnConnectError = OnConnectErrorHandler
socket.OnConnected = OnConnectedHandler
socket.OnTextMessage = socketTextMessageHandler
socket.OnDisconnected = OnDisconnectedHandler

LogDebug("In %v func connecting to URL %v", methodName, url)
socket.Connect()

jsonBytes, e := json.Marshal(payload)
if e != nil {
err = errors.New("build process failed" + e.Error())
LogDebug("Exiting %v func[err =%v]", methodName, err)
return err
}

jsonStr := string(jsonBytes)

LogDebug("In %v Connecting to payload JSON is %v", methodName, jsonStr)
socket.SendText(jsonStr)

<-done
LogDebug("Exiting %v func[err =%v]", methodName, err)
return err

}


func OnConnectErrorHandler(err error, socket gowebsocket.Socket) {
methodName := "OnConnectErrorHandler"
LogDebug("Starting %v parameters [err = %v , socket = %v]", methodName, err, socket)
LogInfo("Disconnected from server ")
done <- true
}

进程应该为运行大约 60-90 秒的进程打开一个 ws 连接(比如执行 npm install)并通过 web socket 获取进程的日志当它完成时,当然还要处理可能发生的问题,例如网络问题或运行过程中的某些错误

最佳答案

所以,@Slabgorb 是正确的 - 如果您查看此处 (https://github.com/sacOO7/GoWebsocket/blob/master/gowebsocket.go#L87),您将看到 OnConnectErrorHandler 在执行对 Connect() Connect() 函数不会启动单独的 goroutine 来处理 websocket,直到连接完全建立并且 OnConnected 回调完成。因此,当您尝试写入无缓冲 channel done 时,您正在阻止调用 run() 函数的相同 goroutine ,然后你自己陷入僵局,因为没有 goroutine 能够从 channel 中读取来解锁你。

所以你可以使用他的解决方案并将其变成一个缓冲 channel ,这会起作用,但我的建议是不要为这种一次性标志行为写入 channel ,而是使用 close 信号代替。为您要终止 run() 的每个条件定义一个 channel ,并在相应的 websocket 处理函数中,在该条件发生时关闭 channel 。在run() 的底部,您可以选择 所有 channel ,并在第一个关闭时退出。它看起来像这样:

package main

import "errors"

func run(appName string) (err error) {

// first, define one channel per socket-closing-reason (DO NOT defer close these channels.)
connectErrorChan := make(chan struct{})
successDoneChan := make(chan struct{})
surpriseDisconnectChan := make(chan struct{})

// next, wrap calls to your handlers in a closure `https://gobyexample.com/closures`
// that captures a reference to the channel you care about
OnConnectErrorHandler := func(err error, socket gowebsocket.Socket) {
MyOnConnectErrorHandler(connectErrorChan, err, socket)
}
OnDisconnectedHandler := func(err error, socket gowebsocket.Socket) {
MyOnDisconectedHandler(surpriseDisconnectChan, err, socket)
}
// ... declare any other handlers that might close the connection here

// Do your setup logic here
// serviceURL, e := GetContext().getServiceURL(appName)
// . . .
// socket := gowebsocket.New(url)

socket.OnConnectError = OnConnectErrorHandler
socket.OnConnected = OnConnectedHandler
socket.OnTextMessage = socketTextMessageHandler
socket.OnDisconnected = OnDisconnectedHandler

// Prepare and send your message here...
// LogDebug("In %v func connecting to URL %v", methodName, url)
// . . .
// socket.SendText(jsonStr)

// now wait for one of your signalling channels to close.
select { // this will block until one of the handlers signals an exit
case <-connectError:
err = errors.New("never connected :( ")
case <-successDone:
socket.Close()
LogDebug("mission accomplished! :) ")
case <-surpriseDisconnect:
err = errors.New("somebody cut the wires! :O ")
}

if err != nil {
LogDebug(err)
}
return err
}

// *Your* connect error handler will take an extra channel as a parameter
func MyOnConnectErrorHandler(done chan struct{}, err error, socket gowebsocket.Socket) {
methodName := "OnConnectErrorHandler"
LogDebug("Starting %v parameters [err = %v , socket = %v]", methodName, err, socket)
LogInfo("Disconnected from server ")
close(done) // signal we are done.
}

这有几个优点:

1) 您不需要猜测哪些回调发生在进程中,哪些回调发生在后台 goroutine 中(并且您不必让所有 channel 都缓冲“以防万一”)

2) 选择多个 channel 可让您找出退出的原因,并可能以不同方式处理清理或日志记录。

注意 1:如果您选择使用 close 信号,您必须为每个源使用不同的 channel 以避免可能导致 channel 获取的竞争条件从不同的 goroutine 关闭两次(例如,当您返回响应时发生超时,并且两个处理程序都触发;第二个处理程序关闭同一 channel 会导致 panic。)这也是您不这样做的原因不想延迟关闭函数顶部的所有 channel 。

注意 2:与您的问题没有直接关系,但是 - 您不需要关闭每个 channel - 一旦它的所有句柄超出范围, channel 将被垃圾收集是否关闭。

关于multithreading - 无法连接时停止 channel ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56692230/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com