Basic NWP

IP层的特点是无连接和不可靠,TCP是建立在IP层之上的应用,自然要实现IP层的这两个问题。

TCP是如何利用IP的不可靠和无连接来达到自己有链接和可靠的目的

TCP首部

TCP的状态变迁

TCP建立连接

TCP断开连接

TCP数据的交互

其他相关内容

IP特点 无连接 不可靠

TCP将应用程序的传输数据分割成合适的数据块,这个数据块叫做报文段,将数据传输给IP这一层,

每发送一个数据块就启动一个定时器,当收到另外一端发送过来的数据包之后呢会进行一次确认,不过这个确认是有延迟的,也就是延迟确认。这是为了效率,假如说传递了10个包过来,如果没有延迟确认就会发送10个回应包,如果稍微延迟一会,这些包都到齐了,只需要发送一次去确认就可以了。TCP会计算首部的校验和,也就是CRC检验。TCP为了保证连接的稳定,会进行流量控制,也就是TCP字段中的窗口大小,在linux内核中就是一段缓冲区。这样防止一下子发送大量数据将慢的一方给堵死了。这是建立在君子的协议上面。如果定时器到了时间之后就会重新发送刚才的数据包,尝试一次,这样尝试几次之后就认为服务器端连接断了,向上层应用反应服务器不可达。

TCP仅仅是将上层应用程序进行了封装,并不知道具体数据流中的含义,也不会对数据流进行解释。TCP的服务是面向字节流的,仅仅是将应用程序的数据以TCP的方式传输到对方的应用程序哪里,并不会对内容做出任何的解释,要解释的是应用程序和TCP没有任何关系。

数据包的重复和数据包的乱序会在TCP这一层解决掉,这样就保证了数据像流水一样的连接不断了。如果乱了,通过确认号进行排序正常,如果是重复了,直接丢掉就可以了。将重复报和乱报直接屏蔽掉了。 TCP包的格式:

源端口    目标端口

    序列号

    确认号

偏移        窗口  

校验和    紧急指针

每发送一个包的时候,就会给这个数据包一个seq(序列号),这个seq和定时器相关,同时,当确认的时候,服务端是对那个数据包进行确认的。

确认号,和确认有关,就是确认上一次你发送的那些包我已经收到了。

data offset 是表示是否有可选项。

TCP的状态

Listen      S 服务器等待客户端来连接

SYN_SENT        C 客户端尝试连接服务器

SYN_RECV          S 服务器确认首次连接

Estab       S C 建立连接,可以双方发送数据了

FIN-wait1       S C 等待对方关闭

FIN-wait2              S C 等待对方关闭

Close_wait       S C 等待自己应用程序关闭

Last_ack       S C 等待最后一次确认消息

Time_wait       S  C 确认对方收的自己的关闭消息 服务器端慎用

Closed       S C 实际上不存在的一种状态

最好不要服务器端主动关闭套接字,

 服务器端最后不要进入TIME_WAIT状态,当进入了TIME_WAIT的时候,这个端口号处于不可用的状态,一定要等待TIMEOUT之后这个SOCKET才可以再次的复用,客户端是无所谓的,服务器端的影响还是挺大的。假如说1000个连接过来了,如果服务器端主动的关闭掉,那么就会有1000个socket pair 进入到不可用的状态,linux系统底层是要保存这些状态的,这样就浪费了服务器端的资源。

断开4次握手是因为TCP是全双工的协议,当一方只接受不发送的状态称为半关闭的状态,TIN_WAIT2就是这种半关闭的状态。

主动关闭的一方,会最终进入TIME_WAIT状态,每个报文要选择一个最大的报文生存时间,传给对方的数据包会在网络中存活一段时间,这个时间是可以设置的,因为一来一回,因此是2倍MSL。为了保证下一次创建一个新链接,上次连接的数据不会对我这次造成混乱。

 当socket进入到TIME_WAIT的时候,操作系统要分配资源,记录这个状态,这个资源不能被释放调,另外如果所有消息是通过代理服务器过来的,很多计算机实际上是通过一台计算机进行中转的,如果服务器将这台代理服务器的socket不能使用,就会有大量的主机进入到TIME_WAIT状态,大量的主机不能使用进入到了TIME_WATI状态。。

Listen 系统会维护一个队列,分为已经连接的,和处于3次握手的,两个连接队列,

如果队列满了,客服端的新链接不连接也不拒绝,让客户端的连接超时,然后进行后续的处理。

数据传输有两种类型,一种是小数据块交互,一种是大块数据。

TCP数据确认有一个时间确认延迟。

Nagle算法,就是说有很多小的数据进行传输,当接受到每个小的数据的时候,先不发送确认,当收到长度达到一定长度的时候才发送确认,尽可能让一次传输饱满一些。在数据量够的时候,一次性发送出去。一般做游戏的时候关闭这个算法,

在传输的时候,为了防止较快的一方将较慢的一方数据给冲垮掉,有一个滑动窗口的东西。

TCP在实现的时候用到了哪些timer?

有4中定时器,一种是重传定时器,坚持定时器,保活定时器,2MSL定时器。

当一个客户端,如果没有收到确认或者是错误,这个时候也不能确认对方是否断掉了,就会重新创送这个消息。

坚持定时器,是处理另外一种状况的,TCP在传输的过程中,会有一个窗口,如果一方发送很快,就会将另外一方的窗口大小挤压成0,如果发生了这种状况。什么时候我才知道对方又可以来收我的信息了呢?这个时候TCP底层用了一个坚持定时器,会定期的来询问,你的窗口大小是不是0呀,能不能接受我的数据呢?

保活定时器,TCP是全双工的,那么假设我不传输给你信息,那么就不能探知对方是否还存在,这条路是否是联通的。一般在TCP底层实现的就是,会启动一个保活定时器,会定时去询问你还在不在,就类似这样的实现。  建议不要打开这样的标记,没有什么太大的意义,如果需要探知对方是否还在,可以在应用程序层,定期的来刷一下这个状态,如果给对方发送消息,对方可以收到,那么对方一定是存活的,就没有必要打开这个标记,因此没必要开这个保活定时器。同时对方是否还存活应该是应用程序的上一层来确认,而不需要TCP自身来确认。

当我主动关闭的时候,为了让消息报在网络中不存在,这个时候就启动了2MSL定时器,在这个歌时范围内,这个套接字是不能使用的。

窗口大小默认是8192字节。

TCP的头部为什么先放端口信息,一般来说当TCP到达了之后首先回根据端口信息来确定有没有应用程序来接受消息。

三次握手有没有被恶意的使用?

恶意的客户端,当第一次发送SYN的时候,服务端会发送SYN && ACK, 但是不发送ACK,那么就悬挂起来了。DoS DDoS这两种攻击。

这样看来TCP协议是有弱点的,因为在3次握手发生在系统层面,应用程序时没有办法来进行处理的,因此单个应用程序时不能处理这种情况的,这个时候需要使用防火墙或者是其他的网络底层来处理这种情况。如果可以处理这种情况,表明3次握手都已经完成了,这个时候这个消息才可以传输到应用层,真正的攻击仅仅发生在网络的这一层,根本没有到应用成这种情况。

消息确认有没有什么问题呢? 可能会出现消息被劫持并修改的可能。

sys/socket 函数和数据结构都定义在这里面

netinet/in.h IPV4和IPV6协议族所需要的信息,

sys/un.h unix即期间通讯的相关信息

arpa/inet/h 处理数字从操作系统字节序到网络字节序的

netdf.b 映射服务到IP地址

服务器端的监听端口,就是bind的需要的端口。

 调用close,TCP的理论模型是一端关闭了发送,这段照样可以接受数据,而调用close函数,则是关闭了两端,和这种模型有点不一样。

send 和 recv这种函数保证的是数据已经到了了操作系统层面,而不保证已经到达了应用程序层面。操作系统已经成功了,在合适的时间会传输到应用程序上面。

设置linger选项,设置窗口大小类似这样的操作。

猜你喜欢

转载自www.cnblogs.com/randyniu/p/9273398.html