无法连接时停止通道
Stop channels when ws not able to connect
我有以下代码可以正常工作,问题是当 socket.Connect()
连接失败 我想停止这个过程,我试过以下代码
但它不起作用,即如果套接字连接失败,程序仍然运行。
我想要发生的是,如果 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 socke
t 获取进程的日志以及它完成的时间,以及当然处理可能发生的问题,如网络问题或一些错误 运行 过程
好的,当您尝试向其中添加内容时,频道正在发生阻塞。尝试使用缓冲区(我使用 1)初始化 done
通道,如下所示:
done = make(chan bool, 1)
所以,@Slabgorb 是正确的 - 如果您查看此处 (https://github.com/sacOO7/GoWebsocket/blob/master/gowebsocket.go#L87),您将看到 OnConnectErrorHandler
在执行对 Connect()
的调用期间被同步调用。在连接完全建立并且 OnConnected
回调完成之前,Connect()
函数不会启动单独的 goroutine 来处理 websocket。因此,当您尝试写入无缓冲通道 done
时,您正在阻塞调用 run()
函数的 same goroutine,并且您自己陷入僵局,因为没有 goroutine 能够从通道中读取来解除阻塞。
所以你可以使用他的解决方案并将其变成缓冲通道,这会起作用,但我的建议是不要为这种 one-time 标志行为写入通道,而是使用close
发信号。为每个要终止的条件定义一个通道 run()
,并在适当的 websocket 处理程序函数中,close
该条件发生时的通道。在run()
下方,可以在所有频道select
,第一个关闭时退出。它看起来像这样:
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) 您无需猜测哪些回调发生 in-process 哪些发生在后台 goroutine 中(并且您不必让所有通道都缓冲 'just in case')
2) 选择多个通道可以让您找出您退出的原因,并可能以不同方式处理清理或日志记录。
注意 1:如果您选择使用 close
信令,您 必须 为每个源使用不同的信道以避免可能导致信道的竞争条件从不同的 goroutines 中关闭两次(例如,当您返回响应时发生超时,并且两个处理程序都会触发;第二个关闭同一通道的处理程序会导致 panic
。)这也是您不这样做的原因想要defer close
所有通道的函数。
注意 2:与您的问题没有直接关系,但是 - 您 不需要 关闭每个通道 - 一旦它的所有句柄超出范围,无论是否关闭,频道都会被垃圾收集。
我有以下代码可以正常工作,问题是当 socket.Connect()
连接失败 我想停止这个过程,我试过以下代码
但它不起作用,即如果套接字连接失败,程序仍然运行。
我想要发生的是,如果 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 socke
t 获取进程的日志以及它完成的时间,以及当然处理可能发生的问题,如网络问题或一些错误 运行 过程
好的,当您尝试向其中添加内容时,频道正在发生阻塞。尝试使用缓冲区(我使用 1)初始化 done
通道,如下所示:
done = make(chan bool, 1)
所以,@Slabgorb 是正确的 - 如果您查看此处 (https://github.com/sacOO7/GoWebsocket/blob/master/gowebsocket.go#L87),您将看到 OnConnectErrorHandler
在执行对 Connect()
的调用期间被同步调用。在连接完全建立并且 OnConnected
回调完成之前,Connect()
函数不会启动单独的 goroutine 来处理 websocket。因此,当您尝试写入无缓冲通道 done
时,您正在阻塞调用 run()
函数的 same goroutine,并且您自己陷入僵局,因为没有 goroutine 能够从通道中读取来解除阻塞。
所以你可以使用他的解决方案并将其变成缓冲通道,这会起作用,但我的建议是不要为这种 one-time 标志行为写入通道,而是使用close
发信号。为每个要终止的条件定义一个通道 run()
,并在适当的 websocket 处理程序函数中,close
该条件发生时的通道。在run()
下方,可以在所有频道select
,第一个关闭时退出。它看起来像这样:
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) 您无需猜测哪些回调发生 in-process 哪些发生在后台 goroutine 中(并且您不必让所有通道都缓冲 'just in case')
2) 选择多个通道可以让您找出您退出的原因,并可能以不同方式处理清理或日志记录。
注意 1:如果您选择使用 close
信令,您 必须 为每个源使用不同的信道以避免可能导致信道的竞争条件从不同的 goroutines 中关闭两次(例如,当您返回响应时发生超时,并且两个处理程序都会触发;第二个关闭同一通道的处理程序会导致 panic
。)这也是您不这样做的原因想要defer close
所有通道的函数。
注意 2:与您的问题没有直接关系,但是 - 您 不需要 关闭每个通道 - 一旦它的所有句柄超出范围,无论是否关闭,频道都会被垃圾收集。