想要远程停止HTTP服务器

huangapple go评论106阅读模式
英文:

Want to stop http server remotely

问题

我想远程停止http服务器(我可以做到),但我也想在停止后收到一条指示已停止的消息。这给我带来了一些问题。我能找到的唯一解决方案如下所示,但我不认为这是理想的。
有人能提供一个更好的解决方案吗?问题是,除非我使用最后的goroutine,否则无法将最终消息发送给客户端。

代码如下:
//*************
func stopServer(ohtWriter http.ResponseWriter, phtRequest http.Request) {// 停止服务器
//
************

var iBytesSent    int
var oOsError    os.Error
var sErmes    string

println("停止服务器")

iBytesSent,oOsError = ohtWriter.Write([]byte("<html>来自服务器的消息 - 服务器已停止。</html>"))

if oOsError != nil {
    sErmes = ". 错误 = " +oOsError.String()
} else {
    sErmes = ". 写入无错误"
}

println("stopServer: 发送的字节数 = " +strconv.Itoa(iBytesSent) +sErmes)

ohtFlusher, tCanFlush := ohtWriter.(http.Flusher)
if tCanFlush {
    ohtFlusher.Flush()
}

go func() {
    time.Sleep(3e9)
    os.Exit(0)
}()

}

英文:

I want to stop the http server remotely (which I can do), but I also want to receive a message indicating that it has been stopped after it has been stopped. That is causing me some problems. The only solution that I could find is as shown below, which I do not consider ideal.
Can anyone provide a better solution. The problem is that the final message sent to the client is not getting through unless I use the goroutine as shown at the end "go func() {".

Code is as follows:
<pre><code>
//*************
func stopServer(ohtWriter http.ResponseWriter, phtRequest http.Request) {// Stop The Server
//
************

var iBytesSent	int
var oOsError	os.Error
var sErmes	string

println(&quot;Stopping Server&quot;)

iBytesSent,oOsError = ohtWriter.Write([]byte(&quot;&lt;html&gt;Message from server - server now stopped.&lt;/html&gt;&quot;))

if oOsError != nil {
    sErmes = &quot;. Error = &quot; +oOsError.String()
} else {
    sErmes = &quot;. No error on write&quot;
}

println(&quot;stopServer: Bytes sent = &quot; +strconv.Itoa(iBytesSent) +sErmes)

ohtFlusher, tCanFlush := ohtWriter.(http.Flusher)
if tCanFlush {
    ohtFlusher.Flush()
}

go func() {
    time.Sleep(3e9)
    os.Exit(0)
}()

}
</code></pre>

答案1

得分: 2

是的,我认为如果没有http包的支持,优雅地关闭是不可能的。这可能会稍微好一些,但仍然会在此请求时关闭任何其他并发请求。也许可以尝试在Go问题跟踪器上提交一个功能请求。更好的方法是打开http包,并添加一个优雅关闭的方法,然后提交它

**编辑:**我猜如果您控制应用程序中的所有http.Handlers,您可以使用适当的线程同步来计算正在处理的请求的数量,并修改下面的代码:a)在调用“shutdown”后拒绝新连接,b)在关闭之前等待所有正在处理的请求完成...

package main

import (
    "http"
    "os"
    "io"
    "log"
    "strconv"
)

func main() {
    http.HandleFunc("/", ServeHTTP)
    http.ListenAndServe(":8081", nil)
}

const responseString = "Shutting down\n"

func ServeHTTP(w http.ResponseWriter, req *http.Request) {
    w.Header().Set("Content-Type", "text/plain; charset=utf-8")
    w.Header().Set("Content-Length", strconv.Itoa(len(responseString)))
    io.WriteString(w, responseString)

    f, canFlush := w.(http.Flusher)
    if canFlush {
        f.Flush()
    }

    conn, _, err := w.(http.Hijacker).Hijack()
    if err != nil {
        log.Fatalf("error while shutting down: %v", err)
    }

    conn.Close()

    log.Println("Shutting down")
    os.Exit(0)
}	
英文:

Yeah I think without support from the http package, a graceful shutdown is not really possible. This is maybe a little bit less cringe-worthy, but will still slam closed any other concurrent requests in flight at the time of this request. Maybe try filing a feature request on the Go issue tracker. Better yet, open up the http package, and add a graceful shutdown method, and submit it.

Edit: I guess if you control all of the http.Handlers in your app, you could keep a count of in-flight requests (using appropriate thread synchronization), and modify the code below to a) refuse new connections once "shutdown" is called and b) wait for all in-flight requests to complete before shutting down...

package main

import (
	&quot;http&quot;
	&quot;os&quot;
	&quot;io&quot;
	&quot;log&quot;
	&quot;strconv&quot;
)

func main() {
	http.HandleFunc(&quot;/&quot;, ServeHTTP)
	http.ListenAndServe(&quot;:8081&quot;, nil)
}

const responseString = &quot;Shutting down\n&quot;

func ServeHTTP(w http.ResponseWriter, req *http.Request) {
	w.Header().Set(&quot;Content-Type&quot;, &quot;text/plain; charset=utf-8&quot;)
	w.Header().Set(&quot;Content-Length&quot;, strconv.Itoa(len(responseString)))
	io.WriteString(w, responseString)

	f, canFlush := w.(http.Flusher)
	if canFlush {
		f.Flush()
	}

	conn, _, err := w.(http.Hijacker).Hijack()
	if err != nil {
		log.Fatalf(&quot;error while shutting down: %v&quot;, err)
	}

	conn.Close()

	log.Println(&quot;Shutting down&quot;)
	os.Exit(0)
}	

答案2

得分: 0

还没有尝试过,但直接使用http.ServerConn可能会起作用。

英文:

Haven't tried it yet, but using http.ServerConn directly might work.

答案3

得分: 0

这是一个足够简单的方法,适用于本地开发。

http://www.sergiotapia.me/how-to-stop-your-go-http-server/


package main

import (
    "net/http"
    "os"

    "github.com/bmizerany/pat"
)

var mux = pat.New()

func main() {
    mux.Get("/kill", http.HandlerFunc(kill))
    http.Handle("/", mux)
    http.ListenAndServe(":8080", nil)
}

func kill(w http.ResponseWriter, r *http.Request) {
    os.Exit(0)
}
英文:

Here's a simple way that's good enough for local development.

http://www.sergiotapia.me/how-to-stop-your-go-http-server/


package main

import (  
    &quot;net/http&quot;
    &quot;os&quot;

    &quot;github.com/bmizerany/pat&quot;
)

var mux = pat.New()

func main() {  
    mux.Get(&quot;/kill&quot;, http.HandlerFunc(kill))
    http.Handle(&quot;/&quot;, mux)
    http.ListenAndServe(&quot;:8080&quot;, nil)
}

func kill(w http.ResponseWriter, r *http.Request) {  
    os.Exit(0)
}

huangapple
  • 本文由 发表于 2011年7月15日 02:08:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/6697917.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定