{"record":{"id":"114fdc4742e1a783","repo":"unknwon/the-way-to-go_ZH_CN","slug":"error-info-error-error","errorCode":null,"errorMessage":"\"ERROR: \" + info + \" \" + error.Error()","messagePattern":"\"ERROR: \" \\+ info \\+ \" \" \\+ error\\.Error\\(\\)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"eBook/15.1.md","lineNumber":293,"sourceCode":"\tcheckError(err, \"Write: wrote \"+string(wrote)+\" bytes.\")\n}\n\nfunc handleMsg(length int, err error, msg []byte) {\n\tif length > 0 {\n\t\tprint(\"<\", length, \":\")\n\t\tfor i := 0; ; i++ {\n\t\t\tif msg[i] == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tfmt.Printf(\"%c\", msg[i])\n\t\t}\n\t\tprint(\">\")\n\t}\n}\n\nfunc checkError(error error, info string) {\n\tif error != nil {\n\t\tpanic(\"ERROR: \" + info + \" \" + error.Error()) // terminate program\n\t}\n}\n```\n（**译者注：应该是由于 Go 版本的更新，会提示 os.EAGAIN undefined，修改后的代码：[simple_tcp_server_v1.go](examples/chapter_15/simple_tcp_server_v1.go)**）\n\n都有哪些改进？\n\n*\t服务器地址和端口不再是硬编码，而是通过命令行参数传入，并通过 `flag` 包来读取这些参数。这里使用了 `flag.NArg()` 检查是否按照期望传入了 2 个参数：\n\n```go\nif flag.NArg() != 2 {\n\tpanic(\"usage: host port\")\n}\n```\n传入的参数通过 `fmt.Sprintf()` 函数格式化成字符串\n```go\nhostAndPort := fmt.Sprintf(\"%s:%s\", flag.Arg(0), flag.Arg(1))\n```","sourceCodeStart":275,"sourceCodeEnd":311,"githubUrl":"https://github.com/unknwon/the-way-to-go_ZH_CN/blob/7a54d34d3657084b6a59e5618bd069b912d571aa/eBook/15.1.md#L275-L311","documentation":"Centralized checkError in the simple TCP server v1 (section 15.1): it takes an error plus an info context string and panics 'ERROR: <info> <err>' on any failure. The section's improvement notes state that all error checks were refactored into checkError, using the error context to trigger panic.","triggerScenarios":"net.ResolveTCPAddr failing on a malformed hostAndPort (bad host or non-numeric port); listener.Accept failing under fd exhaustion (EMFILE); connectionHandler's 25-byte-buffer read/write hitting a connection reset or looping on EAGAIN — whichever error first reaches checkError kills the server.","commonSituations":"Non-numeric port or malformed host passed as CLI arguments; too many open files under load (ulimit -n); clients dropping while the server writes its promo message; note the doc itself flags the os.EAGAIN undefined compile issue in the original listing.","solutions":["Validate the address early with net.SplitHostPort and strconv.Atoi(port) before ResolveTCPAddr","Handle Accept errors with log-and-continue; treat only resolve/listen failures as fatal","Move per-connection read/write errors into the handler: log, close conn, return","Raise 'ulimit -n' or cap concurrent connections if EMFILE appears in the panic message"],"exampleFix":"// before\nfunc checkError(error error, info string) {\n    if error != nil {\n        panic(\"ERROR: \" + info + \" \" + error.Error())\n    }\n}\n\n// after\nfunc checkError(err error, info string) {\n    if err != nil {\n        log.Printf(\"%s: %v\", info, err) // non-fatal: caller decides\n    }\n}","handlingStrategy":"try-catch","validationCode":"// validate the endpoint before ResolveTCPAddr\nhost, portStr, err := net.SplitHostPort(hostAndPort)\nif err != nil {\n    log.Fatal(\"bad address:\", err)\n}\nif p, err := strconv.Atoi(portStr); err != nil || p < 1 || p > 65535 {\n    log.Fatalf(\"bad port %q\", portStr)\n}","typeGuard":null,"tryCatchPattern":"// keep the server alive when a handler panics\nfunc connectionHandler(conn net.Conn) {\n    defer func() {\n        if r := recover(); r != nil {\n            log.Println(\"handler panic:\", r)\n        }\n    }()\n    defer conn.Close()\n    // ... reads/writes; treat EAGAIN as retry, EOF/reset as close\n}","preventionTips":["Validate host:port with net.SplitHostPort + numeric port check before binding","Separate fatal startup errors from per-connection errors; only the former may terminate","Treat EAGAIN as a retry signal, not a termination condition"],"tags":["go","network","tcp","server","panic","error-context"],"backgroundTag":null,"analyzedSha":"7a54d34d3657084b6a59e5618bd069b912d571aa","analyzedAt":"2026-08-15T15:13:06.026Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}