是什么导致 Go 服务器中的 "Connection reset by peer" 错误?
What is causing the "Connection reset by peer" error in the Go server?
我已经用 Go 编写了一个基本的 Web 服务器,但它似乎无法正确处理任何请求,我得到的只是“接收失败:连接被对等方重置”。
我很高兴服务器确实可以正确启动和停止,而且我可以看到它正在侦听我配置的端口 8080。我还排除了解析 YAML 配置文件的问题 - 它肯定会被解析为 http.Server{}。
我不太确定还要检查什么,并且正在努力寻找任何指向正确方向的东西。
我也提前道歉,因为我知道我在下面粘贴了大量代码,但我真的不知道错误来自什么地方。
鉴于服务器是 运行,当我点击“/”endpoint/route 时,我希望得到“Hello from Go!”回来了。
目录结构
❯ tree . | grep -iE 'cmd|server.go|go.mod|go.sum|server.yaml'
├── cmd
│ └── server.go
├── go.mod
├── go.sum
└── server.yaml
server.go
package main
import (
"context"
"errors"
"fmt"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"gopkg.in/yaml.v3"
)
type Config struct {
Port string `yaml:"Port"`
ReadTimeout int `yaml:"ReadTimeout"`
WriteTimeout int `yaml:"WriteTimeout"`
IdleTimeout int `yaml:"IdleTimeout"`
ShutdownTimeout int `yaml:"ShutdownTimeout"`
ErrorLog string `yaml:"ErrorLog"`
}
func main() {
if len(os.Args) != 2 {
log.Fatal("Missing arguments")
}
configFile, err := os.Open(os.Args[1])
if err != nil {
log.Fatal(err)
}
defer configFile.Close()
// TODO: Implement a custom ServeMux + routes
serverConfig := Config{}
yamlDecoder := yaml.NewDecoder(configFile)
err = yamlDecoder.Decode(&serverConfig)
if err != nil {
log.Fatal(err)
}
errorLogFile, err := os.OpenFile(serverConfig.ErrorLog, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
log.Fatal(err)
}
defer errorLogFile.Close()
errorLog := log.New(errorLogFile, "ERROR : ", log.LstdFlags|log.Lshortfile)
server := &http.Server{
Addr: fmt.Sprintf(":%s", serverConfig.Port),
ReadTimeout: time.Duration(serverConfig.ReadTimeout),
WriteTimeout: time.Duration(serverConfig.WriteTimeout),
IdleTimeout: time.Duration(serverConfig.IdleTimeout),
ErrorLog: errorLog,
}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello from Go!")
})
log.Println("Starting the server...")
go func() {
err := server.ListenAndServe()
if !errors.Is(err, http.ErrServerClosed) {
log.Fatal(err)
}
log.Println("Stopped serving new connections")
}()
log.Println("Server started")
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
<-sigChan
ctx, shutdown := context.WithTimeout(context.Background(), time.Duration(serverConfig.ShutdownTimeout)*time.Second)
defer shutdown()
err = server.Shutdown(ctx)
if err != nil {
log.Fatal(err)
}
log.Println("Server gracefully stopped")
}
错误信息
❯ curl -v localhost:8080/
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.64.1
> Accept: */*
>
* Recv failure: Connection reset by peer
* Closing connection 0
curl: (56) Recv failure: Connection reset by peer
如评论中所述,此问题与超时值太短有关 - 每个超时值 5 纳秒。这是因为 time.Duration 表示为两个瞬间之间经过的时间,作为 int64 纳秒计数。所以我需要将其转换为秒数,以获得我所期望的结果。
来自文档:
"A Duration represents the elapsed time between two instants as an int64 nanosecond count. The representation limits the largest representable duration to approximately 290 years."
解决方案:
server := &http.Server{
Addr: fmt.Sprintf(":%s", serverConfig.Port),
ReadTimeout: time.Duration(serverConfig.ReadTimeout) * time.Second,
WriteTimeout: time.Duration(serverConfig.WriteTimeout) * time.Second,
IdleTimeout: time.Duration(serverConfig.IdleTimeout) * time.Second,
ErrorLog: errorLog,
}
我已经用 Go 编写了一个基本的 Web 服务器,但它似乎无法正确处理任何请求,我得到的只是“接收失败:连接被对等方重置”。
我很高兴服务器确实可以正确启动和停止,而且我可以看到它正在侦听我配置的端口 8080。我还排除了解析 YAML 配置文件的问题 - 它肯定会被解析为 http.Server{}。
我不太确定还要检查什么,并且正在努力寻找任何指向正确方向的东西。
我也提前道歉,因为我知道我在下面粘贴了大量代码,但我真的不知道错误来自什么地方。
鉴于服务器是 运行,当我点击“/”endpoint/route 时,我希望得到“Hello from Go!”回来了。
目录结构
❯ tree . | grep -iE 'cmd|server.go|go.mod|go.sum|server.yaml'
├── cmd
│ └── server.go
├── go.mod
├── go.sum
└── server.yaml
server.go
package main
import (
"context"
"errors"
"fmt"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"gopkg.in/yaml.v3"
)
type Config struct {
Port string `yaml:"Port"`
ReadTimeout int `yaml:"ReadTimeout"`
WriteTimeout int `yaml:"WriteTimeout"`
IdleTimeout int `yaml:"IdleTimeout"`
ShutdownTimeout int `yaml:"ShutdownTimeout"`
ErrorLog string `yaml:"ErrorLog"`
}
func main() {
if len(os.Args) != 2 {
log.Fatal("Missing arguments")
}
configFile, err := os.Open(os.Args[1])
if err != nil {
log.Fatal(err)
}
defer configFile.Close()
// TODO: Implement a custom ServeMux + routes
serverConfig := Config{}
yamlDecoder := yaml.NewDecoder(configFile)
err = yamlDecoder.Decode(&serverConfig)
if err != nil {
log.Fatal(err)
}
errorLogFile, err := os.OpenFile(serverConfig.ErrorLog, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
log.Fatal(err)
}
defer errorLogFile.Close()
errorLog := log.New(errorLogFile, "ERROR : ", log.LstdFlags|log.Lshortfile)
server := &http.Server{
Addr: fmt.Sprintf(":%s", serverConfig.Port),
ReadTimeout: time.Duration(serverConfig.ReadTimeout),
WriteTimeout: time.Duration(serverConfig.WriteTimeout),
IdleTimeout: time.Duration(serverConfig.IdleTimeout),
ErrorLog: errorLog,
}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello from Go!")
})
log.Println("Starting the server...")
go func() {
err := server.ListenAndServe()
if !errors.Is(err, http.ErrServerClosed) {
log.Fatal(err)
}
log.Println("Stopped serving new connections")
}()
log.Println("Server started")
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
<-sigChan
ctx, shutdown := context.WithTimeout(context.Background(), time.Duration(serverConfig.ShutdownTimeout)*time.Second)
defer shutdown()
err = server.Shutdown(ctx)
if err != nil {
log.Fatal(err)
}
log.Println("Server gracefully stopped")
}
错误信息
❯ curl -v localhost:8080/
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.64.1
> Accept: */*
>
* Recv failure: Connection reset by peer
* Closing connection 0
curl: (56) Recv failure: Connection reset by peer
如评论中所述,此问题与超时值太短有关 - 每个超时值 5 纳秒。这是因为 time.Duration 表示为两个瞬间之间经过的时间,作为 int64 纳秒计数。所以我需要将其转换为秒数,以获得我所期望的结果。
来自文档:
"A Duration represents the elapsed time between two instants as an int64 nanosecond count. The representation limits the largest representable duration to approximately 290 years."
解决方案:
server := &http.Server{
Addr: fmt.Sprintf(":%s", serverConfig.Port),
ReadTimeout: time.Duration(serverConfig.ReadTimeout) * time.Second,
WriteTimeout: time.Duration(serverConfig.WriteTimeout) * time.Second,
IdleTimeout: time.Duration(serverConfig.IdleTimeout) * time.Second,
ErrorLog: errorLog,
}