11

シンプルな HTTP サービスをホストする Go プログラムがあるので、サイトのリクエストの一部を処理するリバース プロキシとして、ディレクティブを介しlocalhost:8080てパブリックnginxホストをそれに接続できます。proxy_passこれはすべてうまく機能しており、問題はありません。

セキュリティを向上させ、TCP の不要なプロトコル オーバーヘッドを削減するために、ローカル TCP ソケットではなく Unix ドメイン ソケットで HTTP サービスをホストするように Go プログラムを変換したいと考えています。

問題bind(): 問題は、プログラムが終了した後でも、Unix ドメイン ソケットを再利用できないことです。2 回目 (およびそれ以降) に Go プログラムを実行すると、致命的なエラーで終了します"address already in use"

一般的な方法はunlink()、サーバーのシャットダウン時に Unix ドメイン ソケットを使用する (つまり、ファイルを削除する) ことです。ただし、これは Go では注意が必要です。私の最初の試みはdefer、メイン関数 (以下を参照) でステートメントを使用することでしたが、CTRL-C などのシグナルでプロセスを中断すると実行されません。これは期待できると思います。残念ですが、予想外ではありません。

質問unlink():サーバー プロセスがシャットダウンしたときのソケットのベスト プラクティスはありますか (正常または非正常)?

func main()これは、参照をリッスンするサーバーを開始する私の一部です。

// Create the HTTP server listening on the requested socket:
l, err := net.Listen("unix", "/tmp/mysocket")
if err != nil {
    log.Fatal(err)
} else {
    // Unix sockets must be unlink()ed before being reused again.
    // Unfortunately, this defer is not run when a signal is received, e.g. CTRL-C.
    defer func() {
        os.Remove("/tmp/mysocket")
    }()

    log.Fatal(http.Serve(l, http.HandlerFunc(indexHtml)))
}
4

3 に答える 3

8

これが私が使用した完全なソリューションです。質問に投稿したコードは、明確なデモンストレーションを目的とした簡略化されたバージョンです。

// Create the socket to listen on:
l, err := net.Listen(socketType, socketAddr)
if err != nil {
    log.Fatal(err)
    return
}

// Unix sockets must be unlink()ed before being reused again.

// Handle common process-killing signals so we can gracefully shut down:
sigc := make(chan os.Signal, 1)
signal.Notify(sigc, os.Interrupt, os.Kill, syscall.SIGTERM)
go func(c chan os.Signal) {
    // Wait for a SIGINT or SIGKILL:
    sig := <-c
    log.Printf("Caught signal %s: shutting down.", sig)
    // Stop listening (and unlink the socket if unix type):
    l.Close()
    // And we're done:
    os.Exit(0)
}(sigc)

// Start the HTTP server:
log.Fatal(http.Serve(l, http.HandlerFunc(indexHtml)))

これが、Go の作成者が誇りに思うような効果的な Go コードであることを願っています。私には確かにそう見えます。そうでない場合、それは私にとって恥ずかしいことです。:)

好奇心旺盛な人のために、これはhttps://github.com/JamesDunne/go-index-htmlの一部であり、Web サーバーがそのままでは提供しないいくつかの追加機能を備えた単純な HTTP ディレクトリ リスト ジェネレーターです。

于 2013-05-22T21:50:45.223 に答える
2

メイン関数をシグナル ハンドラーで終了し、代わりに他のタスク用に個別の go ルーチンを生成できます。そうすれば、遅延メカニズムを活用して、すべての (シグナルベースかどうかに関係なく) シャットダウンをきれいに処理できます。

func main() {
    // Create the HTTP server listening on the requested socket:
    l, err := net.Listen("unix", "/tmp/mysocket")
    if err != nil {
        log.Fatal(err)
        return
    }
    // Just work with defer here; this works as long as the signal handling
    // happens in the main Go routine.
    defer l.Close()

    // Make sure the server does not block the main
    go func() {
        log.Fatal(http.Serve(l, http.HandlerFunc(indexHtml)))
    }()


    // Use a buffered channel so we don't miss any signals
    c := make(chan os.Signal, 1)
    signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGTERM)

    // Block until a signal is received.
    s := <-c
    fmt.Println("Got signal:", s)

    // ...and exit, running all the defer statements
}
于 2014-08-11T12:10:20.323 に答える