douken1726
2015-09-09 07:53
浏览 78
已采纳

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

I am trying to build a very simple tcp server/client. And I want the program could close the connection when it is interrupted by ctrl-c.

If I only send message or only receive message in the main thread, everything works just fine.

Here is the code for the client side.

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('
')
        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)
}

But after I added the code that just print what it received and run it in another thread, the ctrl-c handler does not work.

This is the code:

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('
')
            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('
')
        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)
}

I am working on Windows 7 now. What is the problem and how can I solve it?

You can find both server side and client side code here: https://gist.github.com/programus/52591a97def30df9dc81

  • 写回答
  • 好问题 提建议
  • 追加酬金
  • 关注问题
  • 邀请回答

1条回答 默认 最新

相关推荐 更多相似问题