您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# 如何配置Go根据端口号启动程序,并守护该进程
## 前言
在现代服务器应用开发中,我们经常需要让程序监听特定端口提供服务。对于Go语言开发者而言,如何优雅地实现基于端口号启动程序并确保进程稳定运行是一个常见需求。本文将深入探讨以下内容:
1. Go程序监听端口的实现原理
2. 通过命令行参数指定端口的方法
3. 使用第三方库创建守护进程
4. 系统级守护方案(systemd/supervisor)
5. 生产环境最佳实践
## 一、Go程序监听端口的基础实现
### 1.1 标准库net/http示例
```go
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, you've requested: %s\n", r.URL.Path)
}
func main() {
http.HandleFunc("/", handler)
port := "8080" // 默认端口
fmt.Printf("Starting server on port %s...\n", port)
http.ListenAndServe(":"+port, nil)
}
package main
import (
"flag"
"fmt"
"net/http"
"os"
)
var port string
func init() {
flag.StringVar(&port, "port", "8080", "server listening port")
flag.Parse()
}
func main() {
fmt.Printf("Starting server on port %s...\n", port)
if err := http.ListenAndServe(":"+port, nil); err != nil {
fmt.Printf("Server failed: %v\n", err)
os.Exit(1)
}
}
使用方式:
go run main.go -port=9090
package main
import (
"log"
"os"
"os/exec"
"syscall"
)
func daemonize() {
cmd := exec.Command(os.Args[0], os.Args[1:]...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin
cmd.SysProcAttr = &syscall.SysProcAttr{
Setsid: true,
}
if err := cmd.Start(); err != nil {
log.Fatalf("Failed to daemonize: %v", err)
}
os.Exit(0)
}
func main() {
// 调用守护函数
daemonize()
// 主程序逻辑...
}
安装:
go get github.com/sevlyar/go-daemon
示例代码:
package main
import (
"flag"
"log"
"os"
"time"
"github.com/sevlyar/go-daemon"
)
var (
port = flag.String("port", "8080", "server port")
daemon = flag.Bool("d", false, "run as daemon")
)
func main() {
flag.Parse()
if *daemon {
cntxt := &daemon.Context{
WorkDir: "./",
Umask: 027,
}
child, err := cntxt.Reborn()
if err != nil {
log.Fatal("Unable to run: ", err)
}
if child != nil {
return
}
defer cntxt.Release()
}
// 主程序逻辑
for {
log.Printf("Server running on port %s (PID: %d)", *port, os.Getpid())
time.Sleep(10 * time.Second)
}
}
创建服务文件 /etc/systemd/system/myapp.service
:
[Unit]
Description=My Go Application
After=network.target
[Service]
Type=simple
User=appuser
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/myapp -port=8080
Restart=always
RestartSec=10
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=myapp
[Install]
WantedBy=multi-user.target
管理命令:
# 重载配置
sudo systemctl daemon-reload
# 启动服务
sudo systemctl start myapp
# 设置开机启动
sudo systemctl enable myapp
# 查看状态
sudo systemctl status myapp
安装Supervisor后,创建配置文件 /etc/supervisor/conf.d/myapp.conf
:
[program:myapp]
command=/opt/myapp/myapp -port=8080
directory=/opt/myapp
user=appuser
autostart=true
autorestart=true
startsecs=10
startretries=3
stdout_logfile=/var/log/myapp.log
stdout_logfile_maxbytes=50MB
stdout_logfile_backups=10
stderr_logfile=/var/log/myapp_err.log
stderr_logfile_maxbytes=50MB
stderr_logfile_backups=10
environment=GIN_MODE="release"
管理命令:
# 更新配置
sudo supervisorctl update
# 启动/停止
sudo supervisorctl start myapp
sudo supervisorctl stop myapp
# 查看状态
sudo supervisorctl status
package main
import (
"net/http"
"time"
)
func healthCheck() {
ticker := time.NewTicker(30 * time.Second)
defer ticker.Stop()
for range ticker.C {
resp, err := http.Get("http://localhost:" + port + "/health")
if err != nil || resp.StatusCode != http.StatusOK {
// 健康检查失败处理
restartService()
}
}
}
func main() {
go healthCheck()
// 主程序逻辑...
}
package main
import (
"context"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
server := &http.Server{
Addr: ":" + port,
Handler: nil,
}
// 优雅关闭
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-quit
log.Println("Shutting down server...")
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
log.Fatal("Server forced to shutdown:", err)
}
}()
log.Println("Server started on port", port)
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatal("ListenAndServe:", err)
}
log.Println("Server exiting")
}
import (
"github.com/sirupsen/logrus"
"gopkg.in/natefinch/lumberjack.v2"
)
func setupLogger() {
logger := logrus.New()
logger.SetOutput(&lumberjack.Logger{
Filename: "/var/log/myapp.log",
MaxSize: 100, // MB
MaxBackups: 10,
MaxAge: 30, // days
Compress: true,
})
logger.SetFormatter(&logrus.JSONFormatter{})
}
package main
import (
"net"
"net/http"
"time"
)
func createHTTPClient() *http.Client {
return &http.Client{
Transport: &http.Transport{
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
MaxIdleConns: 100,
MaxIdleConnsPerHost: 100,
IdleConnTimeout: 90 * time.Second,
},
Timeout: time.Minute,
}
}
推荐使用Prometheus监控:
import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
var (
requestsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total number of HTTP requests",
},
[]string{"method", "path", "status"},
)
)
func init() {
prometheus.MustRegister(requestsTotal)
}
func main() {
http.Handle("/metrics", promhttp.Handler())
// 其他路由...
}
本文详细介绍了Go程序基于端口号启动的多种实现方式,以及各种进程守护方案。实际生产环境中,建议:
通过合理配置,可以确保Go应用程序稳定可靠地长期运行。根据实际需求选择最适合的方案,才能达到最佳效果。
字数统计:约3050字 “`
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。