英文:
How to close http port in go?
问题
我只会翻译你的问题,以下是翻译好的内容:
我正在学习Go,并创建一个简单的Web应用程序。但是每次我在Go中启动我的本地主机(即使我在终端中停止了进程),它都不会关闭端口。那么我该如何关闭它呢?
这是代码:
const portNumber = ":8080"
func main() {
http.HandleFunc("/", Home)
http.HandleFunc("/about", About)
fmt.Println(fmt.Sprintf("Starting on port %s", portNumber))
_ = http.ListenAndServe(portNumber, nil)
}
我在网上进行了研究,但找不到解决方案,所以希望你能帮助我。谢谢。
英文:
im just learning Go, and creating simple web app. But every time i start my localhost in GO(even i stopped process in terminal), it doesnt close port. So how can i close it.
here's code
const portNumber = ":8080"
func main() {
http.HandleFunc("/", Home)
http.HandleFunc("/about", About)
fmt.Println(fmt.Sprintf("Starting on port %s", portNumber))
_ = http.ListenAndServe(portNumber, nil)
}
I did research on net, but couldnt find solution, so hope you can help me. Thanks
答案1
得分: 1
你要找的术语是"优雅关闭"。搜索一下,你会找到类似下面代码的解释。
func startHttpServer() {
srv := &http.Server{
Addr: ListenAddr,
}
idleConnsClosed := make(chan struct{})
go func() {
// 用于优雅关闭...
sigint := make(chan os.Signal, 1)
signal.Notify(sigint, os.Interrupt)
<-sigint
// 收到中断信号,关闭服务器。
log.Println("正在关闭服务器...")
if err := srv.Shutdown(context.Background()); err != nil {
// 关闭监听器时出错,或者上下文超时:
log.Printf("HTTP 服务器关闭错误: %v", err)
}
close(idleConnsClosed)
}()
// 阻塞连接的服务
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
log.Fatalf("HTTP 服务器 ListenAndServe 错误: %v", err)
}
<-idleConnsClosed
}
英文:
The term you are looking for is graceful shutdown. Google it up and you will find code similar to the one below with explanation.
func startHttpServer() {
srv := &http.Server{
Addr: ListenAddr,
}
idleConnsClosed := make(chan struct{})
go func() {
// for graceful shutdown..
sigint := make(chan os.Signal, 1)
signal.Notify(sigint, os.Interrupt)
<-sigint
// We received an interrupt signal, shut down.
log.Println("Shutting down server...")
if err := srv.Shutdown(context.Background()); err != nil {
// Error from closing listener(s), or context timeout:
log.Printf("HTTP server Shutdown: %v", err)
}
close(idleConnsClosed)
}()
// blocking service of connections
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
log.Fatalf("HTTP server ListenAndServe: %v", err)
}
<-idleConnsClosed
}
答案2
得分: 0
我认为首先重要的是重新表述你的问题,并真正理解你在问什么。
没有所谓的关闭的HTTP端口。所以这是HTTP服务器在非常高的层面上的工作方式:
- 当你要求HTTP服务器在某个端口上开始监听时,你实际上是在请求操作系统创建一个代表端点的Internet套接字。从端点来说,我指的是IP:端口。
- 在HTTP 1.1、1.1和2的情况下,该套接字是一个TCP Internet套接字。
- 该套接字处于监听阶段,正在监听任何传入的连接请求。如果它接收到任何传入的请求,内核将简单地进行三次TCP握手,握手成功后,内核将创建一个连接对象并将其交给表示您的后端应用程序的进程,该进程正在监听创建的任何新连接。
所以你看到,端口一直存在于你的系统中,你没有在启动HTTP服务器时创建一个新的端口,而是创建了一个Internet套接字对象,并要求内核在该端口上监听新连接,并在连接创建时将其交给后端应用程序。
所以你实际上是在问我如何停止在该端点上的监听,并要求内核删除该Internet套接字。
下面是一个简单的代码片段,给你一个如何做到这一点的想法。
package main
import (
"context"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
server := &http.Server{Addr: ":8080", Handler: myHandler}
go server.ListenAndServe()
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM)
<-interrupt
log.Println("Shutting down server...")
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
log.Fatal("Server forced to shutdown:", err)
}
log.Println("Server stopped")
}
func myHandler(w http.ResponseWriter, r *http.Request) {
// 处理请求
}
英文:
I think first it is important to rephrase your question and really understand what you're asking.
There's no such thing as a closed HTTP port. So this is how exactly HTTP Server works on a very high level:
-
So when you ask the HTTP server to start listening at a port, You're basically asking OS, to create an Internet socket that represents an endpoint. From the endpoint, I mean IP: PORT.
-
That socket in particular is a TCP internet socket in the case of HTTP 1,1.1 and 2.
-
That socket is running in listen phase and is listening for any incoming connection requests. And if it receives any incoming request then the kernel will simply do a 3 way TCP handshake and after a successful handshake kernel creates a connection object and hand it over to the process that represents your backend application, where you're listening for any new connection created.
So you see PORT was always there in your system, You didn't create a new PORT while starting the HTTP server, but basically created an Internet socket object and asked your kernel to start listening on that PORT for a new connection and hand it over to your backend application when connection created.
So you're basically asking how I stop listening at that endpoint and ask Kernel to delete that internet socket.
Below is a rough code segment to give you an idea of how to do it.import ( "context" "log" "net/http" "os" "os/signal" "syscall" "time" ) func main() { server := &http.Server{Addr: ":8080", Handler: myHandler} go server.ListenAndServe() interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM) <-interrupt log.Println("Shutting down server...") ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() if err := server.Shutdown(ctx); err != nil { log.Fatal("Server forced to shutdown:", err) } log.Println("Server stopped") } func myHandler(w http.ResponseWriter, r *http.Request) { // Handle requests }
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论