Golang中Accept()的工作原理详解
Golang中Accept()的工作原理详解
func main() {
li, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatalln(err)
}
defer li.Close()
for {
conn, err := li.Accept()
if err != nil {
log.Println(err)
continue
}
go handle(conn)
}
}
func handle(conn net.Conn) {
scanner := bufio.NewScanner(conn)
for scanner.Scan() {
ln := scanner.Text()
fmt.Println(ln)
}
defer conn.Close()
}
在这里,Accept() 实现了与客户端的连接。我想知道的是 Accept() 具体是如何工作的?在 net/http 包中,只有函数名和返回值。即使我没有定义它的工作方式,它又是如何运作的呢?
以下是关于 net 包中 Accept() 的说明
类型 Listener 接口 { // Accept 等待并返回监听器的下一个连接 Accept() (Conn, error)
// Close 关闭监听器
// 任何被阻塞的 Accept 操作将被解除阻塞并返回错误
Close() error
// Addr 返回监听器的网络地址
Addr() Addr
}
更多关于Golang中Accept()的工作原理详解的实战教程也可以访问 https://www.itying.com/category-94-b0.html
Accept 是操作系统提供的系统调用。它只是被 Go 运行时封装,以便后续可以进行读写轮询。
如果您想了解更多关于 accept 的信息,可以查阅手册页:http://man7.org/linux/man-pages/man2/accept.2.html
更多关于Golang中Accept()的工作原理详解的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Go语言中,Accept()方法是net.Listener接口的核心方法,它负责在TCP服务器中接受客户端的连接请求。下面详细解释其工作原理:
Accept() 的工作机制
Accept()是一个阻塞调用,它会一直等待直到有客户端连接到服务器。当有新的连接到达时,它会返回一个net.Conn对象,该对象代表与客户端的网络连接。
底层实现
在Linux系统上,Accept()的底层实现基于操作系统的accept()系统调用:
// 简化的底层流程
func (l *TCPListener) Accept() (net.Conn, error) {
// 1. 调用系统accept()接收新连接
fd, err := l.fd.accept()
if err != nil {
return nil, err
}
// 2. 创建新的TCP连接对象
tc := newTCPConn(fd)
// 3. 设置连接属性
if l.lc.KeepAlive >= 0 {
setKeepAlive(fd, true)
setKeepAlivePeriod(fd, l.lc.KeepAlive)
}
return tc, nil
}
完整的工作示例
package main
import (
"bufio"
"fmt"
"log"
"net"
"time"
)
func main() {
// 创建TCP监听器
listener, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatalf("监听失败: %v", err)
}
defer listener.Close()
fmt.Printf("服务器启动,监听地址: %s\n", listener.Addr())
for {
// Accept() 阻塞等待客户端连接
fmt.Println("等待客户端连接...")
conn, err := listener.Accept()
if err != nil {
log.Printf("接受连接失败: %v", err)
continue
}
// 获取客户端地址信息
clientAddr := conn.RemoteAddr().String()
fmt.Printf("新客户端连接: %s\n", clientAddr)
// 为每个连接启动独立的goroutine处理
go handleConnection(conn, clientAddr)
}
}
func handleConnection(conn net.Conn, clientAddr string) {
defer conn.Close()
// 设置读取超时
conn.SetReadDeadline(time.Now().Add(30 * time.Second))
// 创建读取器
reader := bufio.NewReader(conn)
// 向客户端发送欢迎消息
welcomeMsg := fmt.Sprintf("欢迎连接到服务器,你的地址: %s\n", clientAddr)
conn.Write([]byte(welcomeMsg))
for {
// 读取客户端发送的数据
message, err := reader.ReadString('\n')
if err != nil {
fmt.Printf("客户端 %s 断开连接: %v\n", clientAddr, err)
return
}
// 处理接收到的消息
fmt.Printf("来自 %s 的消息: %s", clientAddr, message)
// 回显消息给客户端
echoMsg := fmt.Sprintf("服务器收到: %s", message)
conn.Write([]byte(echoMsg))
}
}
并发连接处理测试
可以使用以下客户端代码测试多个并发连接:
// 客户端测试代码
package main
import (
"fmt"
"net"
"sync"
"time"
)
func clientWorker(id int, wg *sync.WaitGroup) {
defer wg.Done()
conn, err := net.Dial("tcp", "localhost:8080")
if err != nil {
fmt.Printf("客户端 %d 连接失败: %v\n", id, err)
return
}
defer conn.Close()
// 发送消息
msg := fmt.Sprintf("Hello from client %d\n", id)
conn.Write([]byte(msg))
// 读取响应
buffer := make([]byte, 1024)
n, _ := conn.Read(buffer)
fmt.Printf("客户端 %d 收到: %s", id, string(buffer[:n]))
time.Sleep(1 * time.Second)
}
func main() {
var wg sync.WaitGroup
// 启动10个并发客户端
for i := 1; i <= 10; i++ {
wg.Add(1)
go clientWorker(i, &wg)
}
wg.Wait()
}
Accept() 的关键特性
- 阻塞操作:当没有客户端连接时,
Accept()会阻塞当前goroutine - 连接队列:底层维护一个连接队列,处理多个同时到达的连接请求
- 错误处理:网络错误或监听器关闭时会返回错误
- 并发安全:可以在多个goroutine中安全调用,但通常只在一个goroutine中使用
当监听器调用Close()方法时,所有被阻塞的Accept()调用会立即返回错误,这是优雅关闭服务器的关键机制。

