无连接
一旦得知接收端的IP和端口号就可以加个报头直接向下层交付进行传输,不需要建立连接。
不可靠
没有确认、重传机制。无法得知也不关心报文是否到达接收端。
面向数据报
不能够灵活的控制读写数据的次数和数量。
应用层交给UDP多长的报文,UDP原样发送,既不会拆分,也不会合并。
用UDP传输100个字节的数据:
如果发送端调用一次sendto,发送100个字节,那么接收端也必须调用对应的一次recvfrom,接收100个字节;而不能循环调用10次recvfrom,每次接收10个字节。
校验和:如果校验和错误,直接丢弃。
16位UDP长度: 报头和数据的总大小。
标识UDP长度的字段只有16位,也就是说一个UDP能传输的数据最大长度是64K(包含UDP首部)。如果我们需要传输的数据超过64K,就需要在应用层手动的分包,多次发送,并在接收端手动拼装。
UDP的socket既能读,也能写。是全双工通信。
传输控制协议(TCP,Transmission Control Protocol)
URG:紧急指针是否有效
ACK:确认号是否有效
PSH:催促接收端应用程序立刻从TCP缓冲区把数据读走
RST:对方要求重新建立连接,我们把携带RST标识的称为复位报文段
SYN:请求建立连接,携带SYN标识的称为同步报文段
FIN:通知接收方断开连接,我们称携带FIN标识的为结束报文段
TCP将每个字节的数据都进行了编号,即序列号。
每一个ACK都带有对应的确认序列号。告知发送端已收到确认序列号之前的数据,下次从确认序列号开始发送。
当报文在传输的途中由于网络问题或校验出错,接收端未向发送端发送ACK报文,发送端在等待一定时间就会向接收端重新发送报文。
还有一种情况,接收端回应的ACK报文丢失了。此时发送端在超时后进行重传,接收端收到重复报文,这里利用报头中的序列号可以轻易做到去重的效果。
超时的时间:
超时时间应该随着网络环境随之变化。
如果超时时间太长,会影响重传效率,超时时间太短,可能会频繁发送重复的报文。
TCP为了保证无论在任何环境下都能比较高性能的通信,因此会动态计算这个最大超时时间。
Linux中(BSD Unix和Windows也是如此)超时以500ms为一个单位进行控制,每次判定超时重发的超时时间都是500ms的整数倍.
如果重发一次之后,仍然得不到应答,等待2500ms后再进行重传.
如果仍然得不到应答,等待4500ms进行重传.依次类推,以指数形式递增.累计到一定的重传次数, TCP认为网络或者对端主机出现异常,强制关闭连接。
三次握手
服务器状态变化:
[CLOSED -> LISTEN]服务器端调用listen后进入LISTEN状态,等待客户端连接
[LISTEN -> SYN_RCVD]一旦监听到连接请求(同步报文段),就将该连接放入内核等待队列中,并向客户端发送SYN确认报文.
[LISTEN -> ESTABLISHED] 收到客户端的ACK后进入该状态,连接成功建立。
四次挥手:
CLOSE_WAIT 状态:
如果服务器上出现大量的CLOSE_WAIT状态,可能是服多器没有调用close函数关闭socket返回的文件描述符,导致四次挥手没有正确完成。
TIME_WAIT 状态:
作用:
TCP协议规定,主动关闭连接的一方要处于TIME_WAIT状态等待两个MSL(maximum segment lifetime) 的时间后才能回到CLOSED状态
MSL是TCP报文的最大生存时间。TIME_WAIT持续存在2MSL的时长,可以保证在两个传输方向上的尚未被接收或迟到的报文段都已经消失(否则服务器立刻重启,可能会收到来自上一个进程的迟到的教据,但是这种数据很可能是错误的)。
同时也是在理论上保证最活一个报文可靠到达(假设最后一个ACK丢失,那么服务器会再重发一个FIN.这时虽然客户端的进程不在了,但是TCP连还在,仍然可以重发LAST_ACK)。
使服务器立马可以重启并绑定原端口号,不需要等待 TIME_WAIT 结束。
窗口大小指的是无需等待确认应答而可以继续发送数据的最大值.上图的窗口大小就是4000个字节(四个段)
发送前四个段的时候,不需要等待任何ACK,直接发送。
收到第一个ACK后,滑动窗口向后移动,继续发送第五个段的数据。依次类推。
操作系统内核为了维护这个滑动窗口,需要开辟发送缓冲区来记录当前还有哪些数据没有应答。只有确认应答过的数据,才能从缓冲区删除。
窗口大小受限于接收端接收缓冲区大小。
·窗口越大,网络的吞吐率越高。
丢包处理:
如果是ACK报文丢失了,并不影响,可以通过后续的ACK确认报文验证。
如果是报文丢失了,发送端会一直收到重复的ACK。
如果发送端主机连续三次收到了相同的ACK应答,发送端就将对应的数据重新发送。此时接收端收到了重发报文后,再次返回的ACK就是7001了。
这种机制被称为"快重传”。
接收端处理数据的速度是有限的,如果发送端发的太快,导致接收端的缓冲区被打满,这个时候如果发送端继续发送,就会造成丢包,继而引起丢包重传等等一系列连锁反应。
因此TCP支持根据接收端的处理能力,来决定发送端的发送速度,这个机制就叫做流量控制(Flow Control)
接收端将自己可以接收的缓冲区大小放入TCP首部中的窗口大小”字段,通过ACK端通知发送端;窗口大小字段越大。说明网络的香吐量越高;
接收端一旦发现自己的缓冲区快满了,就会将窗口大小设置成一个更小的值通知给发送端;发送端接受到这个窗口之后,就会减慢自己的发送速度;
如果接收端缓冲区满了,就会将窗口置为0。这时发送方不再发送数据,但是需要定期发送一个窗口探测数据段,使接收端把窗口大小告诉发送端。
TCP报头中有一个16位窗口字段,存放了发送方接收缓冲区窗口大小。
TCP首部40字节选项中还包含了一个窗口扩大因子M,实际窗口大小是窗口字段的值左移M位。
TCP引入“慢启动”机制,先发送少量的数据,再逐步增加发送量,探清当前的网络状态,再决定按照多大的速度传输数据。
开始发送时,定义拥塞窗口大小为1每次收到一个ACK应答,拥塞窗口加1。
每次发送数据包时,将拥塞窗口和接收端主机的接收缓冲区大小做比较,取较小的值作为实际发送的窗口。
拥塞窗口的增长速度是指数级别的,初使比较慢,,但是增长速度非常快。
增长到一定程度会遇到阈值,由指数级增长变成线性增长。
·一开始,慢启动阈值等于窗口最大值。
在每次超时重发的时候,慢启动阈值会变成原来的一半,同时拥塞窗口置回1。少量的丢包,我们仅仅是触发超时重传。大量的丢包,我们就认为网络拥塞。
当TCP通信开始后,网络吞吐量会逐渐上升。随着网络发生拥堵,吞吐量会立刻下降。
拥塞控制是TCP协议想尽可能快的把数据传输给对方,但是又要避免给网络造成太大压力的折中方案。
如果接收数据的主机立刻返回ACK应答,这时候返回的窗口可能比较小。
假设接收端缓冲区为10000字节。一次收到了2000字节的数据,如果立刻应答,返回的窗口就是8000字节,但实际上可能处理端处理的速度很快, 10ms之内就把2000字节的数据从缓冲区取走了。
在这种情况下,接收端处理还远没有达到自己的极限,即使窗口再放大一些,也能处理过来;如果接收端稍微等一会再应答,比如等待200ms再应答,那么这个时候返回的窗口大小就是10000字节。
延迟应答受到以下条件限制:
数量限制:每隔N个包应答一次
时间限制:超过最大延迟时间应答一次
大多数情况,客户端服务器在应用层也是"一发一收”的,意味着客户端向服务器发送报文,服务器也会给客户端回一个报文。
那么这个时候ACK就可以和数据一起发送,而不必单独发送。