int connfd = ::accept(m_sockfd, (struct sockaddr*)&addr, &addr_len);
你已经意识到这里有的是传入参数,有的是传出参数,说明你在认真理解系统调用的行为 —— 这是系统编程非常重要的能力。
✅ 先回顾一下 accept()
的函数原型:
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
✅ 参数逐个讲清楚:
参数名 | 类型 | 方向 | 说明 |
---|---|---|---|
sockfd | int | 输入参数 | 监听 socket 的文件描述符,即 m_sockfd ,必须已 listen() |
addr | struct sockaddr* | 输出参数 | 用于返回客户端的地址信息(写入数据) |
addrlen | socklen_t* | 输入/输出参数 | 初始传入 addr 的大小,返回时被修改为实际使用的大小 |
✅ 一句话总结每个参数作用
① m_sockfd
(传入参数)
-
这是你前面用
socket()
+bind()
+listen()
得到的监听 socket。 -
告诉操作系统:“我现在要从这个 socket 上接收一个连接请求”。
② (struct sockaddr*)&addr
(传出参数)
-
这是输出用的结构体,系统会在连接建立后,把客户端的 IP/端口信息写入到
addr
里。 -
所以你需要提前定义这个变量(如
sockaddr_in addr;
),传指针进去。
③ &addr_len
(传入 + 传出)
-
你一开始要告诉操作系统:“这个地址结构的大小是多大”(通常是
sizeof(addr)
)。 -
系统会在调用结束时修改它的值为实际写入的字节数(即客户端地址信息长度)。
-
这是典型的 C 接口“in/out”双向参数。
✅ 图示理解参数传递方向:
调用前:
m_sockfd → 已监听的 socket
addr → 空结构体,等着系统写入客户端地址
addrlen → sizeof(addr)
调用后(成功):
connfd → 新的连接 socket
addr → 填好了客户端 IP/端口
addrlen → 系统写回实际地址长度
✅ 常见错误提醒:
-
❌ 没有给
addr_len
设置初值:socklen_t addr_len; accept(sockfd, (sockaddr*)&addr, &addr_len); // ❌ 未初始化,可能失败
-
✅ 正确做法是:
socklen_t addr_len = sizeof(addr);
✅ 补充:返回值 connfd
-
它是新的 socket fd,专门用于与当前这个客户端通信
-
和
m_sockfd
不同(后者还在继续监听新的连接)
✅ 总结重点:
参数 | 输入 / 输出 | 作用 |
---|---|---|
m_sockfd | 输入 | 哪个监听 socket 来 accept |
addr | 输出 | 客户端地址将被写到这里 |
addr_len | 输入 + 输出 | 告诉系统结构体多大、系统写入实际使用大小 |