三次握手和四次挥手以及对应实现的API

一、三次握手

                                             

                                                                                      图1  tcp的三次握手

在上图中需要注意几点:

1、序列号:其范围在0~(2**32-1)之内,并且可循环利用,用以确定信息是安全且有序的传送。

2、ack存在的意义在于:确定是安全连接,序号未被劫持。

                                                            

                                                                                图2  网络变成核心API

结合图一和图二,有以下几点需要注意:

1、connect 触发三次握手

#include<sys/typs.h>
#include<sys/socket.h>
int connect(int sockfd, const struct sockaddr*serv_addr,socklen_t  addrlen);

        第一个参数 int sockfd确定了自身的IP和port,第二个参数 const struct sockaddr*serv_addr 告诉客户端服务器的IP和port。

2、能否自定义IP/PORT?

        通过bind函数,可以进行IP和PORT的设定。

3、阻塞与非阻塞的区别?

        阻塞与非阻塞的产生都需要两个条件:一是系统调用;二是资源没有准备好。不同之处在于非阻塞在产生系统系统调用之后直接返回错误,而阻塞情况会一直在等待,直到资源准备好为止。

4、API 阻塞与否的原因分析。

        (1)listen():为普通函数。原因在于内核为任何一个给定的监听套接字维护两个队列,即半连接队列(SYN请求连接的报文已有某个客户发送到达服务器,而服务器正在等待完成相应的TCP三次握手过程,这些套接字处于SYN_RCVD状态)和全连接队列(每个已经完成TCP三次握手的客户,这些套接字处于ESTABLISHED状态)。因此,没有等待资源的过程,所以属于普通函数。除此之外,该函数完成三次握手的第二次回包过程。

                                                      

                                                                            图3  TCP三次握手和监听套接字的两个队列

        Q1:listen函数是否能实现非阻塞或阻塞函数,若能,论述其优缺点?

        A:若listen为阻塞函数,则回包过程需要不断的在内核态和用户台之间切换,对于服务器而言是很大的开销。若listen为非阻塞函数,该函数完成三次握手的第二次回包过程。回包的过程是由内核来做,避免了用户态和内核态的切换,减轻服务器的开销。

        Q2:socket()、bind()、listen()在TCP协议栈内能否实现为一个API?

        A:可以,因为这三个函数都为普通函数。但是在编程过程中我们遵循函数式编辑,否则会带来参数过多的问题。分为三个函数来描述,也可以使逻辑更为详细。

        (2)accept():用于从已完成连接队列头部返回下一个已完成连接,如果已完成连接队列为空,那么进程就投入睡眠(假定套接字为默认的阻塞方式)。如果accept成功,那么其返回值是由内核自动生成的一个全新描述符,代表与所返回客户的TCP连接。

        Q:accept为阻塞函数的原因?

        A:若accept()为非阻塞函数的话,每出现一个连接,就会进行一次调用,在多次调用中这些连接并未全部建立好,会造成资源的浪费。

二、四次挥手

                                                

                                                                                      图4  四次挥手

        Q1:触发四次挥手的函数及其运行逻辑?

        A:close()触发四次挥手。close 一个套接字的默认行为是把套接字标记为已关闭,然后立即返回到调用进程,该套接字描述符不能再由调用进程使用,也就是说它不能再作为read或write的第一个参数,然而TCP将尝试发送已排队等待发送到对端的任何数据,发送完毕后发生的是正常的TCP连接终止序列。

           在多进程并发服务器中,父子进程共享着套接字,套接字描述符引用计数记录着共享着的进程个数,当父进程或某一子进程close掉套接字时,描述符引用计数会相应的减一,当引用计数仍大于零时,这个close调用就不会引发TCP的四路握手断连过程。    

        Q2:connect()是否为阻塞函数?

        A:connect()为阻塞函数,其等待三次握手。

        Q3:accept(sockfd,struct sockaddr *addr,addrlen)第二个参数的作用?

        A:这个addr是输出型参数,是一个指向struct sockaddr结构的指针,里面存储着远程连接过来的计算机的信息,如IP地址和端口。其实质是向内核要客户端的IP和PORT.

        Q4:accept返回的fd与listen返回的fd是否为一个fd?

        A:首先,listen后,是肯定占用了对应的端口号的,任何别的尝试使用该端口的操作肯定会报错,accept返回的fd若占用新的端口号,则接下来的读写操作无法进行。而这两个fd的五元组是通过远端的客户端的IP和PORT不同而加以区分的。

        Q5:返回的文件描述符上限是多少,如何调整上限。

        A:为系统能达到的文件描述符的上限(默认是1024)减3,(0,1,2为系统占用,分别代表标准输入,标准输出和标准错误文件),该最大值可以通过命令Ulimit来实现调整。

        Q6:accept()返回的文件描述符的上限取决于全连接队列的上限?

        A:并不是。(待解决)

        Q7:处理百万连接必须准备的有哪些?

        A:1、listen的两个连接队列尽可能大;2、accept返回的个数尽可能多;3、连接五元组尽量使内核内存消耗到最低、。

  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值