TCP协议之三次握手(二)

本节主要研究三次握手出现的一些异常情况和编程相关的知识:

上一节分析了三次握手的过程,本节会回答一些三次握手的小问题,然后利用linux系统调用实践一下简单的网络的编程。

三次握手的常见问题

Q 向一个不存在但合法的公网IP任意端口发送SYN包会出现什么情况?
A 返回ICMP主机不可达。

Q 向一个存在的IP但未绑定的端口发送SYN包会出现什么情况
A 返回 TCP RST segement

Q 第一个SYN包丢失了,客户机会采取什么动作?
A 重传,重试几次后失败,连接失败

Q 为什么建立连接过程不是四次
A Server的SYN &ACK放到一个TCP segment中传给了client

Q 什么时候将会出现4次的 TCP segment交互
A 连接同时断开

Q 第二个SYN2(SYN2 + ACK1)丢失了将会出现什么情况。
A Client收不到SYN2而不发送ACK2, Server端超时重传。

Q:ACK2丢失了将会怎么样
A: 如果出现了大量ACK丢失,未完成的队列就会出现满的状态,从而不能接受SYN1,这就是dos攻击。

三次握手编程实践

参考这里:编程实践

image
connect 函数能为客户端主动连接服务器,建立连接通过三次握手,而这个连接的过程是由内核完成的,不是由函数完成的。connect函数默认会一直阻塞,知道三次握手成功或者超时失败菜户返回。

对于服务器是被动连接的TCP三次握手也不是由这个函数完成的,listen作用仅仅告诉内核一些信息。而且listen函数不会阻塞,它主要做的事情是将套接字和对应度列的长度告诉linux内核,然后listen函数就结束了。
当由一个客户端主动连接,linux内核就自动完成TCP的三次握手。

三次握手的连接队列

listen()函数的第二个参数(backlog)的作用, 告诉内核连接队列的长度。为了更好理解backlog参数,我们必须认识到内核任何一个给定的监听套接口维护一个队列,该队列由两部分构成,分别是完成连接队列,未完成连接队列:

  1. 未完成连接队列,每当服务端收到有一个SYN分节,就会将客户端放入未完成连接队列,而服务器处于 SYN_RECV 状态
  2. 已完成连接队列,当客户端和服务器彻底完成三次握手的过程,客户端从未完成的连接队列升级成为已完成的连接队列,并从未完成的连接队列中清空该客户端, 这些套接口处于ESTABLISHED状态

当来自客户端的SYN到达时, TCP未完成连接队列中创建一个新项,然后知道三次握手的第三个分节到达服务器或者超时为止。

如果三次握手正常完成, 该项就从未完成连接队列移到已完成的队列的队尾。
backlog参数历史上被定义为上面两个队列的大小之和。这个数值默认是128.

accept()函数的功能是从连接队列的头部去除一个已经完成的连接,如果这个队列没有已经完成的连接,accept()函数就会阻塞,知道去除队列中已经完成的用户连接为止。
如果服务器不能及时调用accept函数及时的取走已完成的连接,队列满了会怎样。队列满了以后,服务器不会再对新建立的连接syn进行应答,所以客户端的connect就会返回ETIMEDOUT,但是linux不会这样,只是会延迟收到。具体代码参看编程实践

这个连接队列究竟是怎么工作的有待研究。

posted @ 2017-07-28 11:39  bzt007  阅读(400)  评论(0编辑  收藏  举报