TCP 协议
TCP 协议是一种传输控制协议,是一种面向连接的传输层协议,它提供高可靠性的通信高可靠性:数据无错误,数据无丢失,数据无失序,数据无重复到达。
TCP 协议头部结构
下图是 TCP 协议的头部结构,如图:
16 位端口号:
告知主机该报文段是来自哪里(源端口 Source Port)以及传给哪个上层协议或应用程序(目的端口 Destination Port)的。进行 TCP 通信时,客户端通常使用系统自动选择的临时端口号,而服务器则使用知名服务端口号(比如 DNS 协议对应端口 53,HTTP 协议对应 80,这些端口号可在/etc/services 文件中找到)
32 位序号(seq):
一次 TCP 通信(从 TCP 连接建立到断开)过程中某一个传输方向上的字节流的每个字节的编号。假设主机 A 和主机 B 进行 TCP 通信,A 发送给 B 的第一个 TCP 报文段中,序号值被系统初始化为某个随机值 ISN(Initial Sequence Number,初始序号值)。那么在该传输方向上(从 A 到 B),后续的 TCP 报文段中序号值将被系统设置成 ISN 加上该报文段所携带数据的第一个字节在整个字节流中的偏移。例如,某个 TCP 报文段传送的数据是字节流中的第 1025~2048 字节,那么该报文段的序号值就是 ISN+1025.另外一个传输方向(从 B 到A)的 TCP 报文段的序号值也具有相同的含义。
32 位确认号(ack) :
用作对另一方发送来的 TCP 报文段的响应。其值是收到的 TCP 报文段的序号值加 1。假设主机 A 和主机 B 进行 TCP 通信,那么 A 发送出的 TCP 报文段不仅携带自己的序号,而且包含对 B 发送来的 TCP 报文段的确认号。反之,B 发送出的 TCP 报文段也同时携带自己的序号和对 A 发送来的报文段的确认号。
4 位头部长度(header length):
标识该 TCP 头部有多少个 32bit 字( 4 字节)。因为 4位最大能标识 15 ,所以 TCP 头部最长是 60 字节。
6 位标志位包含如下几项 :
URG 标志,表示紧急指针(urgent pointer)是否有效。
ACK 标志,表示确认号是否有效。我们称携带 ACK 标识的 TCP 报文段为确认报文段。
PSH 标志,提示接收端应用程序应该立即从 TCP 接收缓冲区中读走数据,为接收后续数据 腾出空间(如果应用程序不将接收到的数据读走,它们就会一直停留在 TCP 接收缓冲区中)。
RST 标志,表示要求对方重新建立连接。我们称携带 RST 标志的 TCP 报文段为复位报文 段。
SYN 标志,表示请求建立一个连接。我们称携带 SYN 标志的 TCP 报文段为同步报文段。
FIN 标志,表示通知对方本端要关闭连接了。我们称携带 FIN 标志的 TCP 报文段为结束报文段
16 位窗口大小(window size) :
是 TCP 流量控制的一个手段。这里说的窗口,指的是接收通告窗口(Receiver Window,RWND)。它告诉对方本端的 TCP 接收缓冲区还能容纳多少字节的数据,这样对方就可以控制发送数据的速度,将在后续说明。
16 位校验和(TCP check sum):
由发送端填充,接收端对 TCP 报文段执行 CRC 算法以检验 TCP 报文段在传输过程中是否损坏。注意,这个校验不仅包括 TCP 头部,也包括数据部分。这也是 TCP 可靠传输的一个重要保障。
16 位紧急指针(urgent pointer) :
是一个正的偏移量。它和序号字段的值相加表示最后一个紧急数据的下一字节的序号。因此,确切地说,这个字段是紧急指针相对当前序号的偏移,不妨称之为紧急偏移。TCP 的紧急指针是发送端向接收端发送紧急数据的方法。
TCP 头部选项 :
TCP 头部的最后一个选项字段(options)是可变长的可选信息。这部分最多包含 40 字节,因为 TCP 头部最长是 60 字节(其中还包含前面讨论的 20 字节的固定部分)。典型的 TCP 头部选项结构如下图所示。
TCP 协议实现传输可靠性方式-分段传输
我们在学习 TCP/IP 协议时都知道,TCP 报文段如果很长的话,会在发送时发生分段,在接 收时进行重组,同样 IP 数据报在长度超过一定值时也会发生分片,在接收端再将分片重组。 我们先来了解一下一些名词概念。
MTU( 最大传输单元 )
MTU 是链路层中的网络对数据帧的一个限制,以太网为例, MTU 为 1500 个字节。一个IP 数据报在以太网中传输,如果它的长度大于该 MTU 值,就要进行分片传输,使得每片数据报的长度小于 MTU 。分片传输的 IP 数据报不一定按序到达,但 IP 首部中的信息能让这些数据报片按序组装。IP 数据报的分片与重组是在网络层进完成的。
MSS(最大分段大小) (MSS 是 tcp 里面一个概念 ,只有 tcp 包才有分段概念)
MSS 是 TCP 里的一个概念(首部的选项字段中)。 MSS 是 TCP 数据包每次能够传输的最大数据分段,TCP 报文段的长度大于 MSS 时,要进行分段传输。 TCP 协议在建立连接的时候通常要协商双方的 MSS 值,每一方都有用于通告它期望接收的 MSS 选项( MSS 选项只出现在 SYN 报文段中,即 TCP 三次握手的前两次)。 MSS 的值一般为 MTU 值减去两个首部大小(需要减去 IP 数据包包头的大小 20Bytes 和 TCP 数据段的包头 20Bytes )所以如果用链路 层以太网 MSS 的值往往为 1460 。而 Internet 上标准的 MTU (最小的 MTU ,链路层网络为 x2.5 时)为 576 ,那么如果不设置,则 MSS 的默认值就为 536 个字节。很多时候, MSS 的值最好取 512 的倍数。 TCP 报文段的分段与重组是在运输层完成的。
结论:
到了这里有一个问题自然就明了了,TCP 分段的原因是 MSS , IP 分片的原因是 MTU ,由于一直有 MSS<=MTU ,很明显,分段后的每一段 TCP 报文段再加上 IP 首部后的长度不可能超过 MTU ,因此也就不需要在网络层进行 IP 分片了。因此 TCP 报文段很少会发生 IP 分片的情况。
再来看 UDP 数据报,由于 UDP 数据报不会自己进行分段,因此当长度超过了 MTU 时, 会在网络层进行 IP 分片。同样, ICMP( 在网络层中 ) 同样会出现 IP 分片情况。
TCP 协议实现传输可靠性方式-滑动窗口
TCP 提供一种机制可以让「发送方」根据「接收方」的实际接收能力控制发送的数据量 ,这就是所谓的流量控制。TCP 连接的每一方都有固定大小的缓冲空间,TCP 的接收端只允许发送端发送接收端缓冲区能接纳的数据。当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。TCP 使用的流量控制协议是可变大小的滑动窗口协议 。接收方有即时窗口(滑动窗口),随 ACK 报文发送。(TCP 利用 滑动窗口 实现流量控制和可靠性 )
我们都知道 TCP 是每发送一个数据,都要进行一次确认应答。当上一个数据包收到了应答了,再发送下一个。
这样的传输方式有一个缺点 : 数据包的往返时间越长,通信的效率就越低 。为解决这个问 题,TCP 引入了窗口这个概念。即使在往返时间较长的情况下,它也不会降低网络通信的效率。 那么有了窗口,就可以指定窗口大小, 窗口大小就是指无需等待确认应答,而可以继续发送数据的最大值。
在 TCP“ 三次握手”的过程中, 两台主机交换传输窗口大小, 接收主机把它的接收窗口大小设置成和发送主机的传输窗口大小一致。窗口大小表明任何一次所能传输段的最大个数。
#1 是已发送并收到 ACK 确认的数据:1~31 字节
#2 是已发送但未收到 ACK 确认的数据:32~45 字节
#3 是未发送但总大小在接收方处理范围内(接收方还有空间): 46~51 字节
#4 是未发送但总大小超过接收方处理范围(接收方没有空间):52 字 节以后
当收到之前发送的数据 32~36 字节的 ACK 确认应答后,如果发送窗口的大小没有变化,则滑动窗口往右边移动 5 个字节,因为有 5 个字节的数据被 应答确认,接下来 52~56字节又变成了可用窗口,那么后续也就可以发送 52~56 这 5 个字节的数据了。
TCP 两端都会有一个滑动窗口用来保证数据传输的可靠性,当 A 端给 B 端发送一些数据报 文时,B 端会检查收到的报文并返回给 A 端 ACK 确认消息,如果确认都送达,两端的滑动窗口会向后移动来发送后面的数据,当检查数据漏发或超时情况后有重发处理,保证数据可靠性。
TCP 协议实现传输可靠性方式-三次握手
在 TCP 协议中,为保证客户端和服务器的连接正常,在连接状态需要进行三次握手以达到连接是正常的。
其中:
SYN: 代表请求创建链接---->(就比如打电话问别人你能听到我说话吗)
ACK: 确认标志---->(就比如打电话别人给你回复我能听到)
FIN: 表示请求关闭链接----> (就比如打电话和别人说我话说完了,请求挂电话)
seq:序列号
ack:确认号
首先第一次握手:
客户端向服务器端发送一段 TCP 报文, 其中:标记位为 SYN,表示“请求建立新连接”; 序号为seq=X(X 一般为 1),随后客户端进入 SYN_SENT 阶段( SYN_SENT 表示请求连接状态 )
第二次握手:
服务器端接收到来自客户端的 TCP 报文之后,结束 LISTEN 阶段(LISTEN 表示监听状态),并返 回一段 TCP 报文, 其中:标志位为 SYN 和 ACK,表示“确认客户端的报文 Seq 序号有效 ,服务器能正 常接收客户端发送的数据,并同意创建新连接”(即告诉客户端,服务器收到了你的数据). 其中序号为 Seq=y, 确认号为 ack=x+1,表示收到客户端的序号 seq 并将其值加 1 作为自己确认号 Ack 的值
(也表示下一次期待的序号),随后服务器端进入 SYN-RCVD 阶段( SYN_RCVD 表示同步接收状态 )
第三次握手:
客户端接收到来自服务器端的确认收到数据的 TCP 报文之后,明确了从客户端到服务器的数 据传输是正常的, 结束 SYN-SENT 阶段 。并 返回最后一段 TCP 报文 。其中:标志位为 ACK,表示“确
认收到服务器端同意连接的信号”(即告诉服务器,我知道你收到我发的数据了),序号为 seq=x+1,
表示收到服务器端的确认号 ack,并将其值作为自己的序号值,确认号为 ack=y+1,表示收到服务器
端序号 seq,并将其值加 1 作为自己的确认号 ack 的值;随后客户端进入 ESTABLISHED 阶段
(ESTABLISHED 为连接状态) 。服务器收到来自客户端的“确认收到服务器数据”的 TCP 报文之
后,明确了从服务器到客户端的数据传输是正常的,结束 SYN-SENT 阶段,进入 ESTABLISHED 阶
段。
TCP 协议实现传输可靠性方式-四次挥手
在 TCP 协议中,为保证客户端和服务器的断开正常,在断开阶段需要进行四次挥手以达到断开是正常的。
在第一次挥手:
客户端进程发出连接释放报文 ,并且停止发送数据。 释放数据报文首部 ,FIN=1,其序列号为 seq=u(等于前面已经传送过来的数据的最后一个字节的序号加 1),此时,客户端进入FIN-WAIT-1(终止等待 1)状态。TCP 规定,FIN 报文段即使不携带数据,也要消耗一个序号。
第二次挥手:
服务器 收到连接释放报文, 发出确认报文 ,ACK=1,ack=u+1,并且带上自己的序列号 seq=v,此时,服务端就进入了 CLOSE-WAIT( 关闭等待 )状态。TCP 服务器通知高层的应用进
程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即 客户端已经没有数据要发送 了 ,但是 服务器若发送数据,客户端依然要接受 。这个状态还要持续一段时间,也就是整个
CLOSE-WAIT 状态持续的时间。
客户端 收到服务器的确认请求后,此时,客户端就进入 FIN-WAIT-2(终止等待 2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
第三次挥手:
服务器 将最后的数据发送完毕后,就向客户端 发送连接释放报文 ,FIN=1, ack=u+1,由
于在 半关闭状态 ,服务器很可能又发送了一些数据,假定此时的序列号为 seq=w,此时,服务
器就进入了 LAST-ACK( 最后确认 )状态, 等待客户端的确认
第四次挥手:
客户端 收到服务器的连接释放报文后,必须发出确认,ACK=1 ,ack=w+1,而自己的序列
号是 seq=u+1,此时, 客户端就进入了 TIME_WAIT(时间等待) 状态。注意此时 TCP 连接还没有
释放,必须经过 2 ∗ MSL( MSL 表示最长报文段寿命 )的时间后,当客户端撤销相应的 TCB( Transmission Control Block ,传输控制块 )后,才进入 CLOSED 状态。
服务器 只要收到了客户端发出的确认,立即进入 CLOSED 状态。同样,撤销 TCB 后,就结
束了这次的 TCP 连接。可以看到,服务器结束 TCP 连接的时间要比客户端早一些
思考 1:为什么连接的时候是三次握手,关闭的时候却是四次握手?
答:因为连接时当服务端收到客户端的 SYN 连接请求报文后,可以直接发送 SYN+ACK 报文。 其中 ACK 报文是用来应答的,SYN 报文是用来同步的。但是 关闭连接时 ,当服务端收到 FIN 报文时,很可能并不会立即关闭 SOCKET,所以只能先回复一个 ACK 报文,告诉客户端,"你发的 FIN 报文我收到了"。只有等到服务端所有的报文都发送完了,才能发送 FIN 报文,因此不能一
起发送。故需要四步握手。
思考 2: 为什么 TIME_WAIT 状态需要经过 2MSL(最大报文段生存时间)才能返回到 CLOSE 状
态?
答:虽然按道理,四个报文都发送完毕,我们可以直接进入 CLOSE 状态了,但是我们必须 假象网络是不可靠的 , 有可能最后一个 ACK 丢失 。所以 TIME_WAIT 状态就是 用来重发可能丢失的
ACK 报文 。在 客户端发送出最后的 ACK 回复,但该 ACK 可能丢失 。服务器如果没有收到ACK,将不断重复发送 FIN 片段。所以客户端不能立即关闭,它必须确认服务器接收到了该 ACK。客户端会在发送出 ACK 之后进入到 TIME_WAIT 状态。 客户端会设置一个计时器,等待 2MSL 的时间。如果在该时间内再次收到 FIN,那么客户端会重发 ACK 并再次等待 2MSL 。 所谓的 2MSL 是两倍的 MSL(Maximum Segment Lifetime)。MSL 指一个片段在网络中最大的存活时间,2MSL 就是一个发送和一个回复所需的最大时间。如果直到 2MSL,客户端都没有再次收到 FIN,那么 Client 推断 ACK 已经被成功接收,则结束 TCP 连接。
SYN 洪泛攻击
我们知道在客户端连接服务器的时候,会有一个三次握手的过程,在这个过程中,客户端要向服务器发送连接请求,服务器回复一个确认请求,然后客户端收到确认请求后会回复一个确认请求,那么 SYN 洪泛攻击就是 攻击者发送大量的 SYN 包 , 服务器回应(SYN+ACK)包 , 但是攻击者不回应 ACK 包 ,这样的话, 服务器不知道(SYN+ACK)是否发送成功 ,默认情况下会 重试5 次 (tcp_syn_retries)。那么在这段时间内,可能会有 SYN Flood 的风险(洪泛攻击)。黑客就会利用伪造的 IP 地址像服务端不断的发送请求,却不发送 ACK, 那么本次 TCP 连接就处于挂起的状态,服务端在等待关闭该连接的过程中耗尽了资源(收不到客户端 ACK,就会重复发送Syn-Ack, 消耗内存和 CPU ,直至服务器宕机), 正常的客户端发送的请求就得不到回应 。
TCB 概述
socket 包含两个成分,一个是 IP 地址,一个是端口号。同一个设备可以对应一个 IP 端口,但不同的“设备”用不同的端口号区分开来,于是同一个设备发送给其他不同设备的信息就
不会产生混乱。 在同一时刻,设备可能会产生多种数据需要分发给不同的设备,为了确保数据
能够正确分发,TCP 用一种叫做 TCB,也叫传输控制块的数据结构把发给不同设备的数据封装
起来,我们可以把该结构看做是信封。
一个 TCB 数据块包含了数据发送双方对应的 socket 信息以及拥有装载数据的缓冲区。在两 个设备要建立连接发送数据之前,双方都必须要做一些准备工作,分配内存建立起 TCB 数据块
就是连接建立前必须要做的准备工作。我们还需要了解的一点是 TCP 连接的建立方式,由于
TCP 协议建立在服务器–客户端的模式之上,因此对于两种不同角色的设备,他们发起连接的方
式不一样。
客户端发起连接的方式叫 Active Open 。也就是客户端需要主动向服务器发送消息,表达
自己想建立数据连接的请求 , 通常而言客户端会向服务器发送一个 SYNC 数据包。服务器发起
连接的方式叫 Passive Open ,通来说服务器不可能知道当前时刻有哪个设备想向它发起连接,
因此它只能构建一个端口,然后监听该端口,等待客户端从该端口向它发起连接请求。在
OPEN 阶段无论是客户端还是服务器都需要准备好 TCB 数据结构,但由于服务器不知道要连
接它的客户端信息,因此在构建 TCB 模块时会默认将客户端对应的 socket 数据初始化为 0.
下图可以看到在三次握手前就需要建立 TCB,同理在四次挥手后也要释放 TCB,这个在 1.2.5节四次挥手中提到过。
下图是 TCP 的一个数据结构
struct tcb
{
short tcb_state; /* TCP state */
short tcb_ostate; /* output state */
short tcb_type; /* TCP type (SERVER, CLIENT) */
int tcb_mutex; /* tcb mutual exclusion */
short tcb_code; /* TCP code for next packet */
short tcb_flags; /* various TCB state flags */
short tcb_error; /* return error for user side */
IPaddr tcb_rip; /* remote IP address */
u_short tcb_rport; /* remote TCP port */
IPaddr tcb_lip; /* local IP address */
u_short tcb_lport; /* local TCP port */
struct netif *tcb_pni; /* pointer to our interface */
tcpseq tcb_suna; /* send unacked */
tcpseq tcb_snext; /* send next */
tcpseq tcb_slast; /* sequence of FIN, if TCBF_SNDFIN */
u_long tcb_swindow; /* send window size (octets) */
tcpseq tcb_lwseq; /* sequence of last window update */
tcpseq tcb_lwack; /* ack seq of last window update */
u_int tcb_cwnd; /* congestion window size (octets) */
u_int tcb_ssthresh; /* slow start threshold (octets) */
u_int tcb_smss; /* send max segment size (octets) */
tcpseq tcb_iss; /* initial send sequence */
int tcb_srt; /* smoothed Round Trip Time */
int tcb_rtde; /* Round Trip deviation estimator */
int tcb_persist; /* persist timeout value */
int tcb_keep; /* keepalive timeout value */
int tcb_rexmt; /* retransmit timeout value */
int tcb_rexmtcount; /* number of rexmts sent */
tcpseq tcb_rnext; /* 下一个报文的序号 */
tcpseq tcb_rupseq; /* receive urgent pointer */
tcpseq tcb_supseq; /* send urgent pointer */
int tcb_lqsize; /* listen queue size (SERVERs) */
int tcb_listenq; /* listen queue port (SERVERs) */
struct tcb *tcb_pptcb; /* pointer to parent TCB (for
ACCEPT) */
int tcb_ocsem; /* open/close semaphore */
int tcb_dvnum; /* TCP slave pseudo device number */
int tcb_ssema; /* send semaphore */
u_char *tcb_sndbuf; /* send buffer */
u_int tcb_sbstart; /* start of valid data */
u_int tcb_sbcount; /* data character count */
u_int tcb_sbsize; /* send buffer size (bytes) */
int tcb_rsema; /* receive semaphore */
u_char *tcb_rcvbuf; /* receive buffer (circular) */
u_int tcb_rbstart; /* start of valid data */
u_int tcb_rbcount; /* 接收数据长度 */
u_int tcb_rbsize; /* 接收缓冲区长度 */
u_int tcb_rmss; /* receive max segment size */
tcpseq tcb_cwin; /* 记录了当前窗口可接收的最大报文段序号 */
int tcb_rsegq; /* segment fragment queue */
tcpseq tcb_finseq; /* FIN sequence number, or 0 */
tcpseq tcb_pushseq; /* PUSH sequence number, or 0 */
};
UDP 协议
UDP 协议是一种 面向无连接 的传输层协议,在发送数据前,因为不需要连接,所有可以进行 高效率 的数据传输,但是也不能保证数据的可靠性
UDP 协议头部结构
16 位源端口号:
记录源端口号,在需要对方回信时选用。不需要时可用全 0
16 位目的端口号:
记录目标端口号。这在终点交付报文时必须要使用到。
长度 UDP 数据报的长度 ( 包括数据和首部 ):
其最小值为 8B (即仅有首部没有数据的情况)
校验和 :
检测 UDP 数据报在传输中是否有错,有错就丢弃。该字段时可选的,当源主机不想计算校验和,则直接令该字段为全 0。当传输层从 IP 层收到 UDP 数据报时,就根据首部中的目的端口,把 UDP 数据报通过相应的端口,上交给进程。如果接收方 UDP 发现收到的报文中目的端口号不正确(即不存在对应端口号的应用进程),就丢弃该报文,并由 ICMP 发送“端口不可达”差错报文交给发送方。
UDP 协议和 TCP 协议的优缺点分析
TCP 的优点: 可靠,稳定 TCP 的可靠体现在 TCP 在传递数据之前,会有三次握手来建立连接,
而且在数据传递时,有确认、窗口、重传、拥塞控制机制,在数据传完后,还会断开连接用来
节约系统资源。
TCP 的缺点: 慢,效率低,占用系统资源高,易被攻击 TCP 在传递数据之前,要先建连接,这 会消耗时间,而且在数据传递时,确认机制、重传机制、拥塞控制机制等都会消耗大量的时间,而且要在每台设备上维护所有的传输连接,事实上,每个连接都会占用系统的 CPU、内存等硬件资源。 而且,因为 TCP 有确认机制、三次握手机制,这些也导致 TCP 容易被人利用,实现 DOS、DDOS、CC 等攻击。
UDP 的优点: 快,比 TCP 稍安全,UDP 没有 TCP 的握手、确认、窗口、重传、拥塞控制等机
制,UDP 是一个无状态的传输协议,所以它在传递数据时非常快。没有 TCP 的这些机制,UDP 较 TCP 被攻击者利用的漏洞就要少一些。但 UDP 也是无法避免攻击的,比如:UDP Flood 攻击……
UDP 的缺点: 不可靠,不稳定 因为 UDP 没有 TCP 那些可靠的机制,在数据传递时,如果网络 质量不好,就会很容易丢包
基于上面的优缺点,那么当对网络通讯质量有要求的时候,比如:整个数据要准确无误的传递给对方,这往往用于一些要求可靠的应用,比如 HTTP、HTTPS、FTP 等传输文件的协议, POP、SMTP 等邮件传输的协议应该使用 TCP 协议。 在日常生活中,常见使用 TCP 协议的应用如下: 浏览器,用的 HTTP FlashFXP,用的 FTP Outlook,用的 POP、SMTP Putty,用的
Telnet、SSH QQ 文件传输 …………,当对网络通讯质量要求不高的时候,要求网络通讯速度
能尽量的快,这时就可以使用 UDP。 比如,日常生活中,常见使用 UDP 协议的应用如下: QQ
语音 QQ 视频 TFTP ……
SCTP 协议
SCTP (Stream Control Transmission Protocol)是一种传输协议,在 TCP/IP 协议栈中所处的
位置和 TCP 、 UDP 类似,兼有 TCP/UDP 两者特征。
SCTP 是可以确保数据传输的,和 TCP 类似,也是通过确认机制来实现的。和 TCP 不同的是:
1. TCP 是以字节为单位传输的, SCTP 是以数据块为单位传输的
2. TCP 通常是单路径传输, SCTP 可以多路径传输
TCP 的两端都只能用一个 IP 来建立连接,连接建立之后就只能用这一对 IP 来相互收发消息了。如果这一对 IP 之间的路径出了问题,那这条 TCP 连接就不可用了。 SCTP 不一样的地方是,两端都可以绑定到多个 IP 上,只要有其中一对 IP 能通,这条 SCTP连接就还可以用
3. TCP 是单流有序传输, SCTP 可以多流独立有序 / 无序传输
一条 SCTP 连接里面,可以区分多条不同的流( stream ),不同的流之间的数据传输互不干扰。这样做理论上的好处是,如果其中某一条流由于丢包阻塞了,那只会影响到这一条流,其他的流并不会被阻塞。但是实际上,如果某一条流由于丢包阻塞,其他的流通常也会丢包,被阻塞,最后导致所有的流都被阻塞,SCTP 连接中断。
在同一条 stream 里面, SCTP 支持有序 / 无序两种传输方式,应用程序在调用 sendmsg()的时候,需要指定用哪一条 stream 传输,以及指定这条要发送的消息是需要有序传输还是无序传输的。如果在传输过程中丢包,则有序传递模式可能会在接收端被阻塞,而无序传输模式不会在接收端被阻塞。
4. TCP 连接的建立过程需要三步握手, SCTP 连接的建立过程需要四步握手
TCP 连接建立过程,容易受到 DOS 攻击。在建立连接的时候, client 端需要发送 SYN给 server 端, server 端需要将这些连接请求缓存下来。通过这种机制,攻击者可以发送大量伪造的 SYN 包到一个 server 端,导致 server 端耗尽内存来缓存这些连接请求,最终无法服务。
SCTP 的建立过程需要四步握手, server 端在收到连接请求时,不会立即分配内存缓存起来,而是返回一个 COOKIE 。 client 端需要回送这个 COOKIE , server 端校验之后,从cookie 中重新获取有效信息(比如对端地址列表),才会最终建立这条连接。这样,可以避免类似 TCP 的 SYN 攻击。应用程序对此感知不到,对应用程序来说,不管是 TCP 还是SCTP,都只需要在 server 端 listen 一个 socket , client 调用 connect() 去连接到一个 server 端
5. SCTP 有 heartbeat 机制来管理路径的可用性
SCTP 协议本身有 heartbeat 机制来监控连接 / 路径的可用性。
前面说过,SCTP 两端都可以 bind 多个 IP ,因此同一条 SCTP 连接的数据可以采用不同的 IP 来传输。不同的 IP 传输路径对应一条 path ,不同的 path 都可以由 heartbeat 或者是数据的传输/ 确认来监控其状态。
如果 heartbeat 没相应,或者是数据在某条 path 超时没收到确认导致重传,则认为该path 有一次传输失败。如果该 path 的连续传输失败次数超过 path 的连续重传次数,则认为该 path 不可用,并通知应用程序。如果一条连接的连续传输次数超过设定的 “ 连接最大重传次数” ,则该连接被认为不可用,该连接会被关闭并通知应用程序。
常见因特网应用协议
前两个因特网应用是 ping 和 traceroute,是使用 ICMP 协议进行网络诊断的,traceroute会自动构造 UDP 协议分组来发送并读取所引发的 ICMP 应答。
紧接着是 3 个流行的路由协议,它们展示了路由协议使用的各种传输协议。OSPF 通过原始套接字直接使用 IP,RIP 使用 UDP,BGP 使用 TCP.
接下来 5 个是基于 UDP 的网络应用,然后是 7 个 TCP 网络应用和 4 个同时使用 UDP 和 TCP 的网络应用,最后 5 个是 IP 电话网络应用,它们或者独自使用 SCTP,或者选用 UDP,TCP,STCP。
网络名词概述
互联网的地址-IP 地址
作用︰ 唯一标识一个网络设备 ( 主机、路由器、服务器 )
长度 : 32 位 (IPV4) ,那么一共就有 2^32=43 亿个 IP 地址
范围 ∶ 0.0.0.0-255.255.255.255
表示 : 点分十进制
组成︰ 由网络部分和主机部分组成
IP 地址的组成:网络号+主机号, 如一个 ipv4 地址分为两部分 网段号+主机号 。
网段号: 用来标识某一个局域网段。(是 IP 地址中的连续的高位, 只要网段号相同,就意味着两个 IP 在同一个网段内)
主机号: 用来标识某一个局域网段中的不同主机。(是 IP 地址中的连续的低位)例如:192.168.41.23,这种 ip 一般前 3 个字节表示网络号,也就是 192.168.41,后 1 个字节用来表示主机号,也就是 23,那么 192.168.41.78 就和他属于同一网段的。
基于 技术分类 的话,可以把 ip 分为以下五类
各类 Ip 的范围如下:
其中 A,B,C 类 IP 用于商用地址,D 类用于组播地址,E 类用于科研。
在百度中直接搜索 IP 会显示公网 IP,但是在 cmd 中输入 ipconfig,会显示私有 IP,公网 IP一般是运营商分配的,访问外部网络必须通过公网 IP,但是不可能给世界上每一个电脑都分配一个公网 IP,需要私有 IP,这种 IP 是用于局域网内部管理的(区分局域网内部的不同的主机),不能直接连上互联网。
于是基于 应用 来分的话:
私有地址有 :
10.0.0.0-10.255.255.255
172.16.0.0-172.31.255.255
192.168.0.0-192.168.255.255
特殊地址有:
环回测试 loopback 地址 :127.x.x.x 一般用来表示本地主机
全网地址:0.0.0.0 (默认地址 )
广播地址:255.255.255.255 代表整个局域网
自动配置地址∶ 169.254.x.X 一般通过 DHCP 没法获取到 P 地址时,系统自动给网卡分配的地址
公有地址有:
除了私有地址和特殊地址就是公有地址
子网掩码
子网掩码就是用来指定 IP 地址中,哪些 bits 是网段号,哪些 bits 是主机号,子网掩码中 (netmask)中为 1 的 bit 位对应的 IP 中的位为网段号,为 0 的 bit 位为主机号
如:
一个网络的 IP 为:192.168.2.3
netmask 为:255.255.255.0
那么它的网段号:192.168.2
主机号为 3
子网掩码前面一定是连续的 1,后面是连续的 0
路由表
路由表或称路由择域信息库( RIB ) 是一个存储在 路由器 或者联网计算机中的 电子表格 (文件)或类数据库。路由表存储着指向特定 网络地址 的路径(在有些情况下,还记录有路径的路由 度量值 )。路由表中含有网络周边的拓扑信息。路由表建立的主要目标是为了实现路由协议和静态路由选择。
路由器 的主要工作就是为经过路由器的每个 数据包 寻找一条最佳的传输路径,并将该数据有效地传送到目的站点。由此可见,选择最佳路径的策略即 路由算法 是路由器的关键所在。为了完成这项工作,在路由器中保存着各种传输路径的相关数据—— 路由表(Routing Table ),供 路由选择 时使用,表中包含的信息决定了数据转发的策略。打个比方,路由表就像我们平时使用的地图一样,标识着各种路线,路由表中保存着 子网 的标志信息、网上路由器的个数和下一个路由器的名字等内容。路由表可以是由 系统管理员 固定设置好的,也可以由系统动态修改,可以由路由器自动调整,也可以由 主机 控制。
由 系统管理员 事先设置好固定的路由表称之为静态( static )路由表,一般是在系统安装时就根据网络的配置情况预先设定的,它不会随未来网络结构的改变而改变。动态(Dynamic )路由表是 路由器 根据网络系统的运行情况而自动调整的路由表。路由器根据 路由选择协议 ( Routing Protocol )提供的功能,自动学习和记忆网络运行情况,在需要时自动计算数据传输的最佳路径。
网关
大家都知道,从一个房间走到另一个房间,必然要经过一扇门。同样,从一个网络向另一个网络发送信息,也必须经过一道“ 关口 ” ,这道关口就是网关。 顾名思义 ,网关(Gateway)就是一个网络连接到另一个网络的 “ 关口 ” 。也就是网络 关卡 。
网关(Gateway)又称网间连接器、协议转换器。默认网关在网络层以上实现网络互连,是最复杂的网络互连设备,仅用于两个高层协议不同的网络互连。网关的结构也和路由器类似,不同的是互连层。网关既可以用于广域网互连,也可以用于局域网互连
按照不同的分类标准,网关也有很多种。 TCP/IP 协议 里的网关是最常用的,在这里我们所讲的“ 网关 ” 均指 TCP/IP 协议下的网关。
那么网关到底是什么呢?网关实质上是一个网络通向其他网络的 IP 地址 。比如有网络 A 和网络 B ,网络 A 的 IP 地址范围为 “192.168.1.1~192. 168.1.254” , 子网掩码 为255.255.255.0;网络 B 的 IP 地址范围为 “192.168.2.1~192.168.2.254” , 子网掩码 为255.255.255.0。在没有 路由器 的情况下,两个网络之间是不能进行 TCP/IP 通信的,即使是两个网络连接在同一台 交换机 (或 集线器 )上, TCP/IP 协议 也会根据 子网掩码 (255.255.255.0 )与主机的 IP 地址作 “ 与 ” 运算的结果不同判定两个网络中的主机处在不同的网络里。而要实现这两个网络之间的通信,则必须通过网关。如果网络 A 中的主机发现 数据包 的目的主机不在本地网络中,就把数据包转发给它自己的网关,再由网关转发 给网络 B 的网关,网络 B 的网关再转发给网络 B 的某个主机。网络 A 向网络 B 转发数据 包的过程。
网关地址一般是距离计算机最近的路由器的 ip 地址,取决于路由器设置。
端口号
每一个网络应用程序使用一个 16bit 的端口号唯一的标识自己,网络应用从传输层的角度来分,可以分为 TCP 应用和 UDP 应用,所有 TCP 和 UDP 的端口号相互独立 TCP 可以有 182 号端 口,UDP 也可以使用 182 号,一台主机上面的网络应用程序由:
IP 地址 + 传输层协议(TCP/UDP) + 端口号确定
端口号由 IANA 管理,众所周知的端口号有 1 到 1023:其中 21 号端口表示 ftp 服务器端口,80 号端口是 http 端口
可注册端口号有 1024~49151,一般是分配给用户进程或者应用程序,主要是用户选择安装
的一些程序
动态/私有端口为 49151~65535,一般不固定分配
网络字节序和主机字节序
网络上传输的数据都是字节流,对于一个多字节数值,在进行网络传输的时候,先传递哪个字节?也就是说,当接收端收到第一个字节的时候,它将这个字节作为高位字节还是低位字节处理, 是一个比较有意义的问题;
UDP/TCP/IP 协议规定:把接收到的第一个字节当作高位字节看待,这就要求发送端发送的第一个字节是高位字节;而在发送端发送数据时,发送的第一个字节是该数值在内存中的起始地址处对应的那个字节,也就是说,该数值在内存中的起始地址处对应的那个字节就是要发送的第一个高位字节(即:高位字节存放在低地址处);由此可见,多字节数值在发送之前,在内存中因该是以大端法存放的;
所以说,网络字节序是大端字节序(低地址存放数据的高字节 );
在实际中,当在两个存储方式不同的主机上传输时,需要借助字节序转换函数。
主机字节序就是数据在计算机内部的一个处理方式,是按小端模式还是大端模式,这个取决于系统,一般为小端模式( 高位数据存储于高位内存中 ).
套接字
所谓套接字(Socket) ,就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议栈进行交互的接口
套接字 Socket= ( IP 地址:端口号),套接字的表示方法是点分十进制的 lP 地址后面写上端口号,中间用冒号或逗号隔开。每一个传输层连接唯一地被通信两端的两个端点(即两个套接字)所确定。例如:如果 IP 地址是 210.37.145.1 ,而端口号是 23 ,那么得到套接字就是(210.37.145.1:23)
流式套接字
流式套接字用于提供面向连接、可靠的数据传输服务。该服务将保证数据能够实现无差错、无重复送,并按顺序接收。流式套接字之所以能够实现可靠的数据服务,原因在于其使用了 传输控制协议 ,即 TCP(The Transmission Control Protocol) 协议
数据报套接字
数据报套接字提供一种无连接的服务。该服务并不能保证数据传输的可靠性, 数据有可能在传输过程中丢失或出现数据重复,且无法保证顺序地接收到数据。数据报套接字使用UDP( User DatagramProtocol)协议进行数据的传输。由于数据报套接字不能保证数据传输的可靠性,对于有可能出现的数据丢失情况,需要在程序中做相应的处理
原始套接字
原始套接字与标准套接字( 标准套接字指的是前面介绍的流套接字和数据报套接字 ) 的区别在于:原始套接字可以读写内核没有处理的 IP 数据包,而流套接字只能读取 TCP 协议的数据,数据报套接字只能读取 UDP 协议的数据。因此,如果要访问其他协议发送的数据必须使用原始套接字