网络通信之accept函数简述

/* Await a connection on socket FD.
   When a connection arrives, open a new socket to communicate with it,
   set *ADDR (which is *ADDR_LEN bytes long) to the address of the connecting
   peer and *ADDR_LEN to the address's actual length, and return the
   new socket's descriptor, or -1 for errors.

   This function is a cancellation point and therefore not marked with
   __THROW.  */
extern int accept (int __fd, __SOCKADDR_ARG __addr, socklen_t *__restrict __addr_len);

参数一:socket函数申请到的描述符,接收新连接的描述符

参数二:存储新连接客户端信息的结构体,临时存放外部主机的运输地址

参数三:缓存大小

调用listen后,进程调用accept等待连接请求。accept返回一个新的描述符,指向一个连接到客户的新的插口。原来的插口s仍然是未连接,并准备接收下一个连接。如果name指向一个正确的缓存,accept就会返回对方的地址。处理连接的细节由与插口相关联的协议来完成。对于TCP而言,当一条连接已经被建立(即三次握手已经完成)时,就通知插口层。对于其他的协议,如OSI的TP4,只要一个连接请求到达,tsleep就返回。当进程通过在插口上发送或接收数据来显式证实连接后,连接则算完成。

内核级别的accept处理:

 

 

1.验证参数
accept将缓存大小(*anamelen)赋给namelen,getsock返回插口的file结构。如果插口还没有准备好接收连接(即,还没有调用listen),或已经请求了非阻塞的I/O,且没有连接被送入队列,则分别返回EINVAL或EWOULDBLOCK。
2.等待连接
当出现下列情况时,while循环退出:有一条连接到达;出现差错;或插口不能再接收数据。当信号被捕获之后(tsleep返回EINTR),ccept并不自动重新启动。当协议层通过sonewconn将一条连接插入队列后,唤醒进程。在循环内,进程在tsleep中等待,当有连接到达时,tsleep返回0。如果tsleep被信号中断或插口被设置成非阻塞,则accept返回EINTR或EWOULDBLOCK。
3.异步差错
如果进程在睡眠期间出现差错,则将插口中的差错代码赋给accept中的返回码,清除插口中的差错码后,accept返回。异步事件改变插口状态是比较常见的。协议处理层通过设置so_error或唤醒在插口上等待的所有进程来通知插口层插口状态的改变。因为这一点,插口层必须在每次被唤醒后检查so_error,查看是否在进程睡眠期间有差错出现。
4.将插口同描述符相关联
falloc为新的连接分配一个描述符;调用soqremque将插口从接收队列中删除,放到描述符的file结构中。
5.协议处理
accept分配一个新的mbuf来保存外部地址,并调用soaccept来完成协议处理。如果进程提供了一个缓存来接收外部地址,copyout将地址和地址长度分别从nam和namelen中复制给进程。如果有必要,copyout还可能将地址截掉,如果进程提供的缓存不够大。最后,释放mbuf,使能协议处理,accept返回。

accpet可以设置阻塞和非阻塞两种模式以适用于不同的场景。正常学习过程中不必太过于关心accept内部做了什么事情,只需要关心如何使用它所返回回来的客户端的地址等信息。

原文地址:https://www.cnblogs.com/klxs1996/p/12839882.html