From 18033415c26d32299dacd79d312216f6d9f8369c Mon Sep 17 00:00:00 2001 From: fantasticbin Date: Sun, 15 Jun 2025 21:13:40 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=A4=9A=E8=BF=9B=E7=A8=8B?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E7=9A=84=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- prefork/prefork.go | 152 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 prefork/prefork.go diff --git a/prefork/prefork.go b/prefork/prefork.go new file mode 100644 index 0000000..98a67f4 --- /dev/null +++ b/prefork/prefork.go @@ -0,0 +1,152 @@ +package main + +import ( + "errors" + "flag" + "io" + "log" + "net" + "os" + "os/exec" + "os/signal" + "syscall" +) + +var ( + c = flag.Int("c", 10, "concurrency level, default 10") + prefork = flag.Bool("prefork", false, "use prefork mode") + child = flag.Bool("child", false, "is child process") +) + +func main() { + flag.Parse() + + var ln net.Listener + var err error + + if *prefork { // 如果要启动子进程模式 + ln = doPrefork(*c) + } else { + ln, err = net.Listen("tcp", ":8972") + if err != nil { + panic(err) + } + } + + start(ln) // 处理 net.Listener +} + +func start(ln net.Listener) { + log.Println("started") + for { + conn, e := ln.Accept() + if e != nil { + var ne net.Error + if errors.As(e, &ne) && ne.Temporary() { + log.Printf("accept temp err: %v", ne) + continue + } + + log.Printf("accept err: %v", e) + return + } + + go func() { + _, err := io.Copy(conn, conn) // 实现 echo 协议,将收到的东西原样返回 + if err != nil { + log.Printf("copy err: %v", err) + } + }() + } +} + +func doPrefork(c int) net.Listener { + if *child { + // 子进程:从文件描述符恢复监听器 + listener, err := net.FileListener(os.NewFile(3, "")) + if err != nil { + log.Fatal(err) + } + + // 优雅关闭处理 + sigCh := make(chan os.Signal, 1) + signal.Notify(sigCh, syscall.SIGTERM) + go func() { + <-sigCh + err := listener.Close() + if err != nil { + return + } + }() + + return listener + } + + // 主进程:创建监听器并将其传递给子进程 + addr, err := net.ResolveTCPAddr("tcp", ":8972") + if err != nil { + log.Fatal(err) + } + tcpListener, err := net.ListenTCP("tcp", addr) + if err != nil { + log.Fatal(err) + } + fl, err := tcpListener.File() + if err != nil { + log.Fatal(err) + } + // 主进程不需要保持监听 + if err := tcpListener.Close(); err != nil { + log.Fatal(err) + } + + // 启动子进程并持续监控 + children := make([]*exec.Cmd, c) + + // 处理信号以优雅关闭 + sigCh := make(chan os.Signal, 1) + signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) + + // 启动子进程管理协程 + go func() { + <-sigCh + // 收到信号后通知所有子进程优雅关闭 + for _, child := range children { + if child.Process != nil { + if err := child.Process.Signal(syscall.SIGTERM); err != nil { + log.Fatal(err) + } + } + } + os.Exit(0) + }() + + // 声明子进程启动函数以便递归调用 + var startChildProcess func(int) + startChildProcess = func(i int) { + cmd := exec.Command(os.Args[0], "-prefork", "-child") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.ExtraFiles = []*os.File{fl} + children[i] = cmd + + if err := cmd.Start(); err != nil { + log.Fatalf("启动子进程 %d 失败: %v", i, err) + } + + // 在单独的协程中等待子进程结束并重启 + go func() { + if err := cmd.Wait(); err != nil { + log.Printf("子进程 %d 异常退出: %v,正在重启...", i, err) + startChildProcess(i) // 递归重启 + } + }() + } + // 启动和监控子进程 + for i := range children { + startChildProcess(i) + } + + // 主进程保持运行,但不处理连接 + select {} // 阻塞主进程 +}