Go中的Tcp编程为什么总是能看到handle?

Go中的Tcp编程为什么总是能看到handle?

先搞懂:handle/handler 到底是什么意思?

  • 英文本意
    • handle 作动词是 "处理、应对",作名词是 "处理器、句柄";
    • handler 是 "处理者、处理器"(名词形式)。
  • 编程中的含义:专门负责「处理某个特定事件 / 请求」的函数 / 结构体 / 接口。

在 TCP 编程中,这个 "事件 / 请求" 通常是:

  • 新的客户端连接建立;
  • 客户端发送过来的数据包;
  • 连接断开 / 出错等异常情况。

TCP 编程的 "框架 / 业务" 分离逻辑

TCP 服务端的核心逻辑可以拆成两部分:

  1. 通用框架层:负责底层的网络通信(监听端口、接收连接、读写数据、处理网络异常),这部分是固定的,所有 TCP 服务都需要;
  2. 业务逻辑层:负责处理具体的业务(比如解析客户端发的订单数据、返回查询结果),这部分是定制的,不同业务完全不同。

handle/handler 就是用来承载「业务逻辑层」的载体,框架层只负责 "调用" 它,不关心具体业务。


TCP 编程中 handler 的具体用法

TCP 服务端 - 处理单个连接
go 复制代码
package main

import (
	"bufio"
	"fmt"
	"net"
)

// 核心:定义处理单个 TCP 连接的 handler 函数,所有和业务相关的逻辑,
func handleConn(conn net.Conn) {
	defer conn.Close()
	fmt.Printf("客户端 %s 已连接\n", conn.RemoteAddr())

	// 读取客户端发送的数据(框架层)
	scanner := bufio.NewScanner(conn)
	for scanner.Scan() {
		msg := scanner.Text()
		fmt.Printf("收到客户端 %s 的消息:%s\n", conn.RemoteAddr(), msg)

		// 业务逻辑层(handler 的核心职责)
		response := "服务器已收到:" + msg

		// 发送响应(框架层)
		conn.Write([]byte(response + "\n"))
	}

	fmt.Printf("客户端 %s 已断开连接\n", conn.RemoteAddr())
}

func main() {
	// 框架层:监听端口
	listener, err := net.Listen("tcp", ":8888")
	if err != nil {
		fmt.Println("监听失败:", err)
		return
	}
	defer listener.Close()
	fmt.Println("TCP 服务端已启动,监听端口 8888")

	for {
		conn, err := listener.Accept()
		if err != nil {
			fmt.Println("接收连接失败:", err)
			continue
		}
		go handleConn(conn)
	}
}
定义成接口,让不同业务实现不同的 Handler,彻底解耦
go 复制代码
package main

import (
	"bufio"
	"fmt"
	"net"
)

// 定义 Handler 接口:所有业务处理器都要实现这个接口
type TCPHandler interface {
	Handle(conn net.Conn) // 核心方法:处理连接
}

// 业务 1:echo 处理器(原样返回消息)
type EchoHandler struct{}

func (h *EchoHandler) Handle(conn net.Conn) {
	defer conn.Close()
	scanner := bufio.NewScanner(conn)
	for scanner.Scan() {
		msg := scanner.Text()
		conn.Write([]byte("Echo: " + msg + "\n"))
	}
}

// 业务 2:计算处理器(处理加法请求)
type CalcHandler struct{}

func (h *CalcHandler) Handle(conn net.Conn) {
	defer conn.Close()
	scanner := bufio.NewScanner(conn)
	for scanner.Scan() {
		msg := scanner.Text()
		// 模拟解析加法请求:比如 "10+20"
		conn.Write([]byte("计算结果:30\n")) // 简化逻辑
	}
}

// 通用 TCP 服务端(框架层)
func StartTCPServer(addr string, handler TCPHandler) {
	listener, _ := net.Listen("tcp", addr)
	defer listener.Close()
	fmt.Println("TCP 服务端启动:", addr)

	for {
		conn, _ := listener.Accept()
		// 调用传入的 handler 处理连接(控制反转)
		go handler.Handle(conn)
	}
}

func main() {
	// 启动 echo 服务(换业务只需要换 handler)
	// StartTCPServer(":8888", &EchoHandler{})

	// 启动计算服务
	StartTCPServer(":8888", &CalcHandler{})
}

四、为什么偏偏是 handle/handler

  1. 语义精准handler 直接点明 "这个东西是用来处理某个事件的",比随便起个名字(比如 process/do)更清晰;
  2. 行业通用 :不只是 Go 的 TCP 编程,Java 的 Netty、Python 的 Socket 编程、前端的事件处理(event handler)都用这个命名 ------ 属于程序员的 "通用语言",看到就知道是 "处理器";
  3. 职责明确 :看到 handleConn/TCPHandler,立刻能区分 "这是处理连接的业务逻辑",和 "监听端口、读写数据的框架逻辑" 划清界限;
  4. 符合 Go 语言习惯 :Go 标准库中大量使用 Handler 命名(比如 http.Handler),TCP 编程自然沿用这个习惯,保持一致性。
相关推荐
mOok ONSC3 分钟前
Spring Boot 3.4 正式发布,结构化日志!
java·spring boot·后端
normanhere3 分钟前
外网线路负载均衡和DNS分流
网络
野犬寒鸦6 分钟前
计网复习Day01
服务器·后端·网络协议·面试
遇见你...8 分钟前
B02 SpringMVC的请求和相应
java·开发语言
VelinX9 分钟前
【个人学习||spring boot】
spring boot·后端·学习
浅念-14 分钟前
Linux 进程与操作系统
linux·运维·服务器·网络·数据结构·笔记·网络协议
计算机安禾15 分钟前
【数据结构与算法】第20篇:二叉树的链式存储与四种遍历(前序、中序、后序、层序)
c语言·开发语言·数据结构·c++·学习·算法·visual studio
_MyFavorite_20 分钟前
JAVA重点基础、进阶知识及易错点总结(17)线程安全 & synchronized 同步锁
java·开发语言·安全
_MyFavorite_21 分钟前
JAVA重点基础、进阶知识及易错点总结(13)File 类 + 路径操作
java·开发语言
Lyyaoo.21 分钟前
Spring Boot自动配置
java·spring boot·后端