socket编程之accept()

本文详细介绍了Linux下accept()函数的作用和用法,包括参数解析、返回值和可能遇到的错误。accept()用于接收监听套接字的连接请求,创建新的套接字并返回文件描述符。当队列无连接时,阻塞型的accept()会等待,而设置为非阻塞时则会返回EAGAIN或EWOULDBLOCK错误。此外,文章还提到了accept4()的额外参数flags以及如何通过select()、poll()或epoll()避免阻塞。最后,文章列举了各种可能的错误情况和错误码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

4 accept()

用于接收监听套接字中保存的套接字连接。它提取监听套接字 sockfd 的挂起连接队列上的第一个连接请求,创建一个新的已连接套接字,并返回引用该套接字的新文件描述符。accept()执行的系统调用并不会对原始的监听套接字产生任何其他影响。

4.1 包含头文件
#include <sys/types.h>       
#include <sys/socket.h>
4.2 函数主体
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);

参数解释:

  • int sockfd

​ 参数sockfd必须是指向执行listen()调用以后的监听套接字

  • struct sockaddr *addr

​ 参数 addr 是指向 sockaddr 结构的指针。 此结构用已知的对等套接字的地址填充。返回地址 addr 的确切格式由套接字的地址系列决定(在socket()函数中指定的)。需要注意的是,该地址返回的是客户端的外网IP,而客户端使用的IP一般均为内网IP,所以我们根据这个地址返回的IP是访问不到客户端主机的。如果addr设置为NULL时,表示不关心客户端的地址,addrlen也应该设置为NULL。

  • socklen_t *addrlen

​ addrlen类一个特殊的参数,传入参数为调用者提供的缓存区,而传出参数为客户端地址结构体的实际长度,因此,每次调用accept()之前都应该为该参数赋初值。如果提供的缓冲区太小,则返回的地址将被截断;在这种情况下,addrlen 将返回一个大于提供给调用的值。

  • int flags

​ 这个参数时accept4()所特有的,当flags = 0时,accept()和accept4()是完全相同的。但该参数还可以传递以下两个参数,以实现对socket()的进一步控制:SOCK_NONBLOCK、SOCK_CLOEXECS,这两个参数的含义在第1小节socket()中已经说明,此处不再赘述。

对accept()作进一步补充:

  1. accept()为阻塞型函数,如果队列上不存在挂起的连接,并且套接字未标记为非阻塞,则 accept() 将阻塞调用进程,直到存在连接为止。 如果套接字标记为非阻塞,并且队列上不存在挂起的连接,则 accept() 将失败,并显示错误 EAGAIN 或 EWOULDBLOCK。
  2. 如果不想设置套接字为非阻塞但又需要在调用accept()时避免对进程造成阻塞,则可以选择使用 select()、poll() 或 epoll(),这些函数会有新连接传入是通知调用者有可读事件,然后就可以调用accept()函数了。对于select()、poll() 或 epoll()函数会在IO复用专栏进行说明。
4.3 返回值

​ 调用成功时函数返回一个非负整数,该整数是已接受套接字的文件描述符。调用失败时,返回-1,错误类型如下:

错误类型解释
EAGAIN或者EWOULDBLOCK套接字被标记为非阻塞,且当前没有可接收的连接.
EBADF描述符非法
ENOTSOC描述符指向一个文件,而不是一个套接字
EOPNOTSUPP作为参数的套接字不是 **SOCK_STREAM.**类型
EFAULT参数 addr 不在用户可写地址空间之内.
EPERM防火墙规则禁止连接
ENOBUFS,ENOMEM没有足够内存. 这个错误一般来说意味着内存分配受套接字缓冲区所限, 而不是没有系统内存.
EINVAL非监听套接字,或者 addrlen 无效(例如,为负数)。
ECONNABORTED连接以中止
4.4 结束

在 Linux 上,accept() 返回的新套接字不会从侦听套接字继承文件状态标志,如O_NONBLOCK和O_ASYNC。若对返回的新套接字有相关要要求,需要重新设置所有必需的标志。本接提到的内容代码实现可以参考第2节bind()中代码。

另外,最后对可能出现所有错误类新做一个总结,可以在文件 /usr/include/sys/errno.h 中找到 Errno。

在这里插入图片描述

参考:常见的错误码
所讲的函数以及应用:代码传送门

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值