TCP

Overview
- 面向连接:通信双方都必须先建立连接,然后才能开始数据的读写。双方都必须为该连接分配必要的内核资源,以管理连接的状态和连接上数据的传输。TCP连接是全双工的,即双方的数据读写都可以通过一个连接来进行。完成数据交换之后,通信双方都必须断开连接以释放系统资源。
- 字节流:发送端执行的写操作次数和接收端执行的读操作次数之间没有任何数量关系,应用程序对数据的发送和接收时都没有边界限制的。
- 可靠: [确认 + 重传 + checksum]
-
- 首先,TCP协议采用发送应答机制,即发送端的每个TCP报文段都必须得到接收方的应答,才认为这个TCP报文传输成功。
- 其次,TCP协议采用超时重传机制,发送端在每发送一个TCP报文段之后启动定时器,如果在定时时间内未收到应答,它将重发该报文段。
- 最后,因为TCP报文段最终是以ip数据报发送的,而ip数据报到达接收端可能乱序,重复,所以tcp协议还会对接收到的TCP报文段重排、整理,再交付给应用层。 [序号seq number]
- 校验和CheckSum。
* 注意:TCP并不能保证数据一定会被收方接收到(即使有超时重发机制,发方可能因为一直收不到收方的ack而断开连接。不过此时收方是有可能已经收到了的)。
TCP能做到的是,如果有可能就把数据传到收方,否则就(通过放弃重传并且中断连接这一手段)通知用户。
因此准确说 TCP 也不是 100% 可靠的协议,它所能提供的是数据的可靠递送或故障的可靠通知。
TCP连接管理
TCP连接的创建
![]()
- 三次握手(three-way handshake)过程创建一个连接。
- 三次握手的过程:
- client发出请求连接报文段,其中报文控制位SYN=1, 初始序号seq=x。client进入SYN-SENT(同步已发送)状态。
- server端收到请求报文段后,向client发送确认报文段,其中SYN=1, ACK=x+1, 同时为自己选择一个初始序号seq = y。server端进入SYN-RCVD(同步收到)状态。
- client收到server端的确认报文段后,还要向server端发送一个确认报文段,其中ACK = 1, ack = y + 1, 而自己的序列号 seq = x + 1。 这个报文段已经可以携带数据,如不携带则不消耗序列号,而下一个报文段序号仍为seq = x + 1。
- 至此,TCP连接已经建立,client进入ESTABLISHED(已建立连接)状态,当服务端收到确认后,也进入ESTABLISHED(已建立连接)状态,之后便可以正式传递数据了。
-
- 如果server端接到了client发送的SYN后回了 SYN/ACK 后client掉线了,server端没有收到client端回来的ACK,那么,这个连接处于一个中间状态,既没成功也没失败。于是,server如果在一定时间内没有收到的话会重发SYN/ACK。在linux下,默认重试次数为5次,重试的间隔时间从1s开始每次都翻倍,因此一共需要1 + 2 + 4 + 8 + 16 + 32 = 63s后TCP才会断开这个连接。
- 关于为什么是三次握手,而不是四次or两次?
- “为了防止已经失效的连接请求报文段突然又传送到sever端,从而产生错误”。
- 举个例子,client发出的第一个连接请求报文段并没有丢失,而是在某个网络节点长时间滞留了,以至延迟到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段,但server受到后误认为其为一个新的连接请求,就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么这个连接就已经建立了,server端会浪费资源来等待数据传输。采用“三次握手”便可避免这种现象。
- 这个问题的本质是信道不可靠,但是通信双方需要就某个问题达成一致,三次通信是理论上的最小值。所以三次握手不是TCP本身的要求,而是为了满足“在不可靠的信道上可靠地传输信息”这一要求导致的。
TCP关闭连接
- 四次挥手才能关闭连接。

- 四次挥手过程:
- 首先,TCP连接处于ESTABLISHED状态,client停止发送数据,并发出一个FIN报文段。其FIN = 1, seq = u (u为client传输数据最后一字节的序号加1)。client进入FIN-WAIT-1(终止等待1)状态。
- server端回复确认报文段,ack = u + 1, seq = v, server端进入CLOSE-WAIT(关闭等待)状态。现在TCP连接处于半开半闭状态,server端如果继续发送数据,client依然接收。
- client收到确认报文,进入FIN-WAIT-2状态。server端发送完数据后,发出FIN报文段,FIN = 1, ack = u + 1, 然后进入LAST-ACK(最后确认)状态。【因为TCP是全双工的,我们需要等待server端发送完数据】
- client回复确认报文段,ack = w + 1, (w为半开半闭状态时,收到的最后一个字节数据的编号),seq = u + 1, 然后进入TIME-WAIT(时间等待)状态。
- 此时连接还没有释放,需要时间等待状态结束后(4min)连接两端才会CLOSED。设置时间等待是因为,有可能最后一个确认报文丢失而需要重传。
- server通过返回确认报文段使连接进入CLOSE_WAIT状态。其含义是等待server应用程序关闭连接。通常server检测到client关闭连接后,也会立即给client发一个结束报文段来关闭连接。这将使连接转移到LAST_ACK状态,以等待client对结束报文段的最后一次确认。一旦确认完成,连接就彻底关闭了。
TCP状态转换图

SYN攻击
- SYN Flood
- 攻击client在短时间内伪造大量不存在的IP地址,向server不断发送SYN包。由于IP是不存在的,server会不断地重发(SYN-ACK)直至超时。
- --> 这些伪造的SYN包将长时间占用未连接队列,正常的SYN请求被丢弃,导致目标系统运行缓慢。
- SYN 攻击是一种典型的 DoS/DDoS 攻击。
- 如何检测?
- 检测 SYN 攻击非常的方便,当你在服务器上看到大量的半连接状态时,特别是源IP地址是随机的,基本上可以断定这是一次SYN攻击。在 Linux/Unix 上可以使用系统自带的 netstats 命令来检测 SYN 攻击。 [关于半连接状态:server发送SYN-ACK之后,在收到client的ACK之前的TCP连接称为半连接]
- 如何防御? SYN攻击不能完全被阻止,除非将TCP协议重新设计。我们所做的是尽可能的减轻SYN攻击的危害,常见的防御 SYN 攻击的方法有如下几种
- 缩短超时(SYN timeout)时间
- 增加最大半连接数
- 过滤网关防护
- SYN cookies技术
TCP KeepAlive
- 连接建立之后,如果长时间没收到数据,TCP需要决定是否继续保持这个连接。
- TCP协议通过一种巧妙的方式去解决这个问题,当超过一段时间之后,TCP自动发送一个数据为空的报文给对方,如果对方回应了这个报文,说明对方还在线,链接可以继续保持,如果对方没有报文返回,并且重试了多次之后则认为链接丢失,没有必要保持链接。
- http KeepAlive VS tcp KeepAlive:
- http KeepAlive是为了让tcp获得更久一点,以便在同一个连接上传送多个http,提供效率(减少连接建立的消耗)。
- 而tcp KeepAlive是TCP的一种检测TCP连接状态的保鲜机制。
- 一般来说,服务器程序不会用到tcp/ip的KeepAlive,而是把KeepAlive放到业务层,自己实现KeepAlive。
- --> 这样的好处是可以减少程序对特定协议的依赖。
- 所以,未开启tcp KeepAlive的话需要在上层做KeepAlive,否则连接不会自动断开。
可靠传输
overview
- ARQ(Automatic Repeat-reQuest)即自动重传请求。
- 它通过使用确认和超时两个机制,在不可靠服务的基础上实现可靠的信息传输。
- ARQ协议包括停止等待ARQ协议和连续ARQ协议。
停止等待协议
- 是指发送完一个分组就停止发送,等待对方的确认,只有收到确认后,才发送下一个分组。
- 优点:简单
- 缺点:信道利用率太低。
- 出现差错的情况:利用超时重传:发送方需要在确认前暂存副本 & 分组和确认信息都应该有各自的编号。
连续ARQ协议
- 改进信道利用率问题:连续发送一组数据包,然后等待这些数据包的ACK。
- 发送方采用流水线传输。
- 结合滑动窗口协议(如下)来使用。
- 超时重传:
- 时间选择:由于数据链路层和传输层的往返时间概率分布存在很大差异,因此有必要选择合适的超时重传时间。
报文段的平均往返时延RTT是由各个报文段的往返时延样本加权平均得出来的。计算公式为:平均往返时延RTT=α×(旧的RTT)+(1-α)×(新的往返时延样本),1 ≤ α < 1 典型的值为α为7/8.即使有一个好的RTT,要选择一个合适的超时重传时间RTO(Restransmission Time out)仍然不是一个容易的事情。, 显然RTO要大于RTT。其计算公式为 RTO = β × RTT, β > 1, 推荐是2
- 时间选择:由于数据链路层和传输层的往返时间概率分布存在很大差异,因此有必要选择合适的超时重传时间。
- 选择确认SACK(Selctive ACK): 若收到的报文段只是未按序号,中间还缺少一些序号的数据,则采用选择确认的方法来传送缺少的数据,而不重传已经正确接收到的数据。
- 如果这些字节的序号都在接收窗口内,那么接收方就先收下这些数据,但要把这些信息准确的告诉发送放,使发送方不要在重复发送这些已经收到的数据。
- TCP首部没有哪个字段能够提供上述这些字节快的边界信息。如果要使用选择确认,那么在建立TCP连接时,就要在TCP首部的选项上加上“允许SACK”的选项。
- 接收方一般都采用累积确认方式,即对按序达到的最后一个分组发送确认。
滑动窗口协议
- 窗口不断前移,协议允许发送方在停止并等待确认前发送多个数据分组。因而该协议可以加速数据传输,还可以控制流量。

- 发送窗口:表示在没有收到收方确认的情况下,可以连续把窗口内的数据发送出去。凡是已发送的数据,在未收到确认之前都必须暂时保存,以便超时重传使用。
- 发送窗口由前沿 + 后沿的位置共同确认。后沿在收到确认的情况下会前移。
- 以字节为单位。

- TCP利用滑动窗口协议来实现流量控制。
UDP
-
UDP 是一个简单的传输层协议。和 TCP 相比,UDP 有下面几个显著特性:
- UDP 缺乏可靠性。UDP 本身不提供确认,序列号,超时重传等机制。UDP 数据报可能在网络中被复制,被重新排序。即 UDP 不保证数据报会到达其最终目的地,也不保证各个数据报的先后顺序,也不保证每个数据报只到达一次
- UDP 数据报是有长度的。每个 UDP 数据报都有长度,如果一个数据报正确地到达目的地,那么该数据报的长度将随数据一起传递给接收方。而 TCP 是一个字节流协议,没有任何(协议上的)记录边界。
- UDP 是无连接的。UDP 客户和服务器之前不必存在长期的关系。UDP 发送数据报之前也不需要经过握手创建连接的过程。
- UDP 支持多播和广播。 [TCP是点对点的]
HTTP
- Hyper Text Transfer Protocol(超文本传输协议):是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。
- HTTP 是基于 TCP/IP 协议的应用层协议。它不涉及数据包(packet)传输,主要规定了客户端和服务器之间的通信格式,默认使用80端口。
- HTTP构建于TCP/IP协议之上,默认端口号是80
- HTTP是无连接无状态的。 [这是标准http协议,但随着发展...]
- 无状态:
- 无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
- 早期这么做是因为,client和server之间交换数据的间隙大(突发性、瞬时性),从而大部分通道空闲。
- --> 因此将其设计为请求时建连接、请求完释放连接,以尽快将资源释放出来服务其他客户端。
- 但随着时间推移,引入了KeepAlive功能使得client到server的连接持续有效。
- HTTP协议工作于客户端-服务端架构之上。浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求。Web服务器根据接收到的请求后,向客户端发送响应信息。
工作原理
- 建立连接:一个http client(通常是浏览器),与web server的http端口(默认80),建立一个TCP socket连接。
- 发送http请求:通过TCP socket,client向web server发送一个文本的请求报文(包含请求行、请求头部、空行和请求数据)
- server接受请求并返回HTTP响应:web server解析请求,定位请求资源。服务器将资源复本写到TCP套接字,由客户端读取。一个响应由状态行、响应头部、空行和响应数据4部分组成。
- 释放TCP连接:
- 若connection 模式为close,则服务器主动关闭TCP连接,客户端被动关闭连接,释放TCP连接。
- 若connection 模式为keepalive,则该连接会保持一段时间,在该时间内可以继续接收请求。
- client浏览器解析html内容
- 在浏览器地址输入一个url会发生什么
- 浏览器识别url:http, ftp等协议
- 域名相关:(DNS)
- 浏览器本地cache
- 查找本地hosts文件(域名:IP地址)
- 查询本地域名服务器
- 查询根域名服务器(recursive search)
- ARP过程:由目标IP地址确定MAC地址
- 根据IP地址访问服务器 [其实是socket]
- 和server建立TCP连接
- 浏览器给web server发送一个HTTP请求 [该请求报文作为TCP三次握手的第三个报文发送给server]
- (在这个过程中可能会发生重定向:web server给浏览器返回一个永久重定向,然后浏览器重新访问新网址
- web server返回一个HTML response
- 释放TCP连接(对应上面说的是否KeepAlive)
- 浏览器接下来的处理
- 浏览器开始渲染HTML
- 浏览器去请求其他嵌入在HTML中的资源(图片,CSS,js)
- 浏览器可能进一步发送异步的AJAX请求。
Http KeepAlive[长连接]
- TCP连接的新建成本很高,因为需要客户端和服务器三次握手,并且开始时发送速率较慢(slow start)。所以,HTTP 1.0版本的性能比较差。随着网页加载的外部资源越来越多,这个问题就愈发突出了。
-
1.1 版的最大变化,就是引入了持久连接(persistent connection),即TCP连接默认不关闭,可以被多个请求复用,不用声明
Connection: keep-alive。 -
客户端和服务器发现对方一段时间没有活动,就可以主动关闭连接。不过,规范的做法是,客户端在最后一个请求时,发送
Connection: close,明确要求服务器关闭TCP连接。 - 目前,对于同一个域名,大多数浏览器允许同时建立6个持久连接。
Pipelining
- pipelining管道机制:在同一个TCP连接里面,客户端可以同时发送多个请求。
- --> 进一步提高效率
- 举例来说,客户端需要请求两个资源。以前的做法是,在同一个TCP连接里面,先发送A请求,然后等待服务器做出回应,收到后再发出B请求。管道机制则是允许浏览器同时发出A请求和B请求,但是服务器还是按照顺序,先回应A请求,完成后再回应B请求。
无状态(の发展)
- 无状态是指协议对于事务处理没有记忆能力,服务器不知道客户端是什么状态。
- --> 每个请求都是独立的。
- 优点:解放了服务器,响应快。
- 缺点:每次请求会传输大量重复的内容信息。
- 客户端与服务器进行动态交互的 Web 应用程序出现之后,HTTP 无状态的特性严重阻碍了这些应用程序的实现,毕竟交互是需要承前启后的,简单的购物车程序也要知道用户到底在之前选择了什么商品。于是,两种用于保持 HTTP 连接状态的技术就应运而生了,一个是 Cookie,而另一个则是 Session。
- 会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。
Cookie
- Cookie可以保持登录信息到用户下次与服务器的会话,换句话说,下次访问同一网站时,用户会发现不必输入用户名和密码就已经登录了。
- 当然,不排除用户手工删除Cookie。而还有一些Cookie在用户退出会话的时候就被删除了,这样可以有效保护个人隐私。
- Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。
- --> 所以cookie的功能需要浏览器的支持。
Session
- 与Cookie相对的一个解决方案是Session,它是通过服务器来保持状态的。
- 当客户端访问服务器时,服务器根据需求设置 Session,将会话信息保存在服务器上,同时将标示 Session 的 SessionId 传递给客户端浏览器,浏览器将这个 SessionId 保存在内存中,我们称之为无过期时间的 Cookie。浏览器关闭后,这个 Cookie 就会被清掉,它不会存在于用户的 Cookie 临时文件。
- --> 以后浏览器每次请求都会额外加上这个参数值,服务器会根据这个 SessionId,就能取得客户端的数据信息。
- session的生命周期:
- 为了获得更高的存取速度,服务器一般把Session放在内存里。每个用户都会有一个独立的Session。
- Session在用户第一次访问服务器的时候自动创建。
- Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,并维护该Session。
- session的有效期:session有超时时间。
- session仍然需要浏览器的支持:因为session不能根据http连接来判断是否为同一客户。
- --> server 向client发送一个名为JSESSIONID的cookie。
- 只在当前浏览器内有效,不能在各浏览器之间共享。关闭浏览器就会失效。
- (因此同一机器的两个浏览器窗口访问服务器时,会生成两个不同的Session。但是由浏览器窗口内的链接、脚本等打开的新窗口(也就是说不是双击桌面浏览器图标等打开的窗口)除外。这类子窗口会共享父窗口的Cookie,因此会共享一个Session。 子窗口会共用父窗口的Session。)
URL地址重写
- 可以看到,上述cookie和session都依赖于浏览器对于cookie的支持。
- URL地址重写是对客户端不支持Cookie的解决方案。
- URL地址重写的原理是将该用户Session的id信息重写到URL地址中。服务器能够解析重写后的URL获取Session的id。这样即使客户端不支持Cookie,也可以使用Session来记录用户状态。
满地都是六便士,她却抬头看见了月亮。

浙公网安备 33010602011771号