You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Go的net.Listener中暂停和恢复接受新连接?

实现TCP连接的暂停与恢复控制

我们可以通过通道信号配合动态启停监听goroutine的方式实现需求:暂停时终止监听逻辑(不再接受新连接),恢复时重新启动监听。

核心实现代码

package main

import (
	"log"
	"net"
	"os"
	"os/signal"
	"syscall"
	"time"
)

func main() {
	// 控制监听启停的信号通道
	startChan := make(chan struct{})
	stopChan := make(chan struct{})

	// 绑定系统信号作为用户输入触发(可替换为其他输入方式,比如终端命令)
	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, syscall.SIGUSR1, syscall.SIGUSR2)

	// 初始启动监听
	go startListener(startChan, stopChan)
	startChan <- struct{}{}

	for {
		sig := <-sigChan
		switch sig {
		case syscall.SIGUSR1:
			log.Println("暂停接受新连接")
			stopChan <- struct{}{}
		case syscall.SIGUSR2:
			log.Println("恢复接受新连接")
			go startListener(startChan, stopChan)
			startChan <- struct{}{}
		}
	}
}

func startListener(startChan <-chan struct{}, stopChan <-chan struct{}) {
	// 等待启动信号
	<-startChan

	// 创建TCP监听器
	l, err := net.Listen("tcp", ":2000")
	if err != nil {
		log.Fatalf("监听初始化失败: %v", err)
	}
	defer l.Close() // 退出时自动关闭监听器

	log.Println("已启动TCP监听,端口:2000")

	for {
		select {
		case <-stopChan:
			log.Println("监听goroutine已退出,停止接受新连接")
			return
		default:
			// 设置短超时,避免Accept永久阻塞导致无法响应停止信号
			tcpListener := l.(*net.TCPListener)
			if err := tcpListener.SetDeadline(time.Now().Add(500 * time.Millisecond)); err != nil {
				log.Printf("设置监听超时失败: %v", err)
				return
			}

			conn, err := l.Accept()
			if err != nil {
				// 超时错误属于正常情况,继续循环检查停止信号
				if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
					continue
				}
				log.Printf("接受连接失败: %v", err)
				return
			}

			// 异步处理连接,避免阻塞监听逻辑
			go handleConnection(conn)
		}
	}
}

func handleConnection(conn net.Conn) {
	defer conn.Close()
	log.Printf("新连接建立: %s", conn.RemoteAddr().String())
	// 此处添加自定义的连接处理逻辑
}

关键逻辑说明

  • 启停信号控制:startChan用于触发监听启动,stopChan用于触发监听goroutine退出。退出时通过defer l.Close()关闭监听器,确保Accept立即返回错误,goroutine快速终止。
  • 避免永久阻塞:给TCP监听器设置500毫秒超时,即使没有新连接,也能定期检查停止信号,保证暂停指令即时生效。
  • 动态重启机制:每次恢复时创建新的监听goroutine和监听器实例,确保恢复后能正常接受新连接。

测试方法

  • 启动程序后,执行kill -SIGUSR1 <进程ID>发送暂停信号,程序停止接受新连接。
  • 执行kill -SIGUSR2 <进程ID>发送恢复信号,程序重新启动监听。

内容的提问来源于stack exchange,提问作者d9ngle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 09:35:29