网络编程之accept函数和accept函数在三次握手中的位置

时间:2024-04-09 20:35:22

accept函数实际上是在三次握手之后,具体原因请看文章结尾具体解释。

基本TCP客户端/服务器程序的套接字函数

网络编程之accept函数和accept函数在三次握手中的位置

accept函数由TCP服务器调用,用于从已完成连接队列队头返回下一个已完成连接(从这不难看出accept是在三次握手之后,文章最后具体说明,已完成连接队列请转连接自行观看)。如果已完成队列为空,那么进程被投入睡眠(嘉定套接字为默认的阻塞方式)。

#include<sys/socket.h>

int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);

返回:若成功返回非负描述符,若出错则为-1


    参数cliaddr和addrlen用来返回已连接的对端进程(客户)的协议地址。addrlen是值-结果参数:调用前,我们将由*addrlen所引用的整数值置为由cliaddr所指的套接字地址结构的长度,返回时,该整数值即为由内核存放在该套接字地址结构内的确切字节数。

    如果accept连接成功,那么其返回值是有内核自动生成的一个全新描述符,代表与所返回客户的TCP连接。在讨论accept,我们称它的第一个参数为监听套接字描述符,返回值为已连接套接字描述符。区分这两个套接字分厂重要,一个服务器通常仅仅创建一个监听套接字,他在该服务器的生命周期内一直存在。内核为每个服务器进程接收的客户连接创建一个已连接套接字。当服务器完成对某个给定客户的服务时,已连接套接字就被关闭。

    本函数最多返回三个值:一个既可能是新套接字描述符也可能是出错指示的整数、客户进程的协议地址以及改地址的大小。如果我们对返回客户协议地址不感兴趣,那么可以把cliaddr和addrlen均值为空指针。

    

    accept应该位于第三次握手之后,我们来看看TCP连接过程:

    初始:客户端处于CLOSED状态,而服务器端从CLOSED状态变为LISTEN状态

    第一步:客户端发送一个SYN***

    第二步:服务器端接收来自客户端的连接请求,并返回ACK+SYN

    第三步:客户端接收消息,返回ACK

    在第三步之后,服务器接收到消息,连接就完成了。这样就可以调用accept函数获得此连接。

    accept其实也可以在第三步,原因是,此时accept函数要给此次连接分配资源,最初是想这样设计;但是,设想如果有10000甚至更多个客户端都和该服务器连接,发送SYN,服务端收到之后,这些客户端却不再理会服务端的回复,然而此时服务端的资源却都用accept()分配了。这就是所谓的“DDOS攻击”。

    为了解决这个问题,accept()于是被放在三次握手之后。

    当然,这样也不能保证不能被攻击,当然这是后话。