gpt4 book ai didi

go - 为什么当我在 go 中添加另一个阻塞线程时信号处理程序不起作用?

转载 作者:数据小太阳 更新时间:2023-10-29 03:28:15 27 4
gpt4 key购买 nike

我正在尝试构建一个非常简单的 TCP 服务器/客户端。我希望程序在被 ctrl-c 中断时可以关闭连接。

如果我只在主线程中发送消息或只接收消息,一切正常。

这是客户端的代码。

package main 

import (
"fmt"
"os"
"os/signal"
"syscall"
"net"
"bufio"
"io"
"time"
)

const (
TIMEOUT = 10
)

func main() {
if len(os.Args) < 2 {
fmt.Println(usage(os.Args[0]))
return
}

var timeout time.Duration
if len(os.Args) > 2 {
timeout, _ = time.ParseDuration(os.Args[2])
}
if timeout == 0 {
timeout = time.Duration(TIMEOUT * time.Second)
}

conn, err := net.DialTimeout("tcp", os.Args[1], timeout)

if err != nil {
fmt.Println("Error connecting: ", err.Error())
return
}

defer conn.Close()

c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)

go func() {
fmt.Println("wait ctrl-c")
for _ = range c {
fmt.Println("close on ctrl-c")
conn.Close()
}
}()

for {
message, err := bufio.NewReader(os.Stdin).ReadString('\n')
if err == io.EOF {
fmt.Fprint(conn, message)
break
} else if err != nil {
fmt.Println("Error reading: ", err.Error())
break
} else {
fmt.Fprintf(conn, message)
}
}
}

func usage(filename string) string {
return fmt.Sprintf("Usage: %s <address (ex. localhost:8016, google.com:http, [2001:db8::1]:http, etc.)> [timeout (ex. 10s, 300ms, etc.)]", filename)
}

但是在我添加了仅打印接收到的内容并在另一个线程中运行它的代码之后,ctrl-c 处理程序不起作用。

这是代码:

package main 

import (
"fmt"
"os"
"os/signal"
"syscall"
"net"
"bufio"
"io"
"time"
)

const (
TIMEOUT = 10
)

func main() {
if len(os.Args) < 2 {
fmt.Println(usage(os.Args[0]))
return
}

var timeout time.Duration
if len(os.Args) > 2 {
timeout, _ = time.ParseDuration(os.Args[2])
}
if timeout == 0 {
timeout = time.Duration(TIMEOUT * time.Second)
}

conn, err := net.DialTimeout("tcp", os.Args[1], timeout)

if err != nil {
fmt.Println("Error connecting: ", err.Error())
return
}

defer conn.Close()

c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)

go func() {
fmt.Println("wait ctrl-c")
for _ = range c {
fmt.Println("close on ctrl-c")
conn.Close()
}
}()
// code added.
go func() {
for {
message, err := bufio.NewReader(conn).ReadString('\n')
if err == io.EOF {
fmt.Print(message)
break
} else if err != nil {
fmt.Println("Error remote reading: ", err.Error())
break
} else {
fmt.Print(message)
}
}

conn.Close()

os.Exit(0)
}()

for {
message, err := bufio.NewReader(os.Stdin).ReadString('\n')
if err == io.EOF {
fmt.Fprint(conn, message)
break
} else if err != nil {
fmt.Println("Error reading: ", err.Error())
break
} else {
fmt.Fprintf(conn, message)
}
}
}

func usage(filename string) string {
return fmt.Sprintf("Usage: %s <address (ex. localhost:8016, google.com:http, [2001:db8::1]:http, etc.)> [timeout (ex. 10s, 300ms, etc.)]", filename)
}

我现在正在使用 Windows 7。问题是什么,我该如何解决?

您可以在此处找到服务器端和客户端代码: https://gist.github.com/programus/52591a97def30df9dc81

最佳答案

我做了更多的调查,发现问题的关键点不是线程,而是信号处理程序是否有足够的时间运行。

我做了一个简单的程序来重现Windows 7下的问题以及解决方法。

package main

import (
"fmt"
"io"
"os"
"os/signal"
)

func main() {
c := make(chan os.Signal, 1)
//q := make(chan bool, 1)
signal.Notify(c, os.Interrupt, os.Kill)

go func() {
sig := <- c
fmt.Println(sig)
//close(q)
}()

count, err := io.Copy(os.Stdout, os.Stdin)
fmt.Println(count, err)
//select {
//case <- q:
//}
}

您会发现信号有时可能无法打印出来。但是在我取消注释 q channel 相关代码之后。它总是有效。

所以我认为这是因为程序退出得太快,无法让信号处理程序运行。

希望这个问答可以帮助到有同样问题的其他人。

此外,我为简单的 tcp 服务器/客户端制定了一个解决方案并更新了要点。

https://gist.github.com/programus/52591a97def30df9dc81

关于go - 为什么当我在 go 中添加另一个阻塞线程时信号处理程序不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32473923/

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