------------恢复内容开始------------
------------恢复内容开始------------
tcp的特点
- tcp是面向连接的,服务器与客户端的连接会经历三次握手,断开会敬礼四次握手
- tcp提供可靠性:当发送数据时,会要求对端进行确认
- tcp会估计RTT(Round-Trip Time),这个时间根据网络的距离和实验不同
- tcp给每个字节一个序号,因此保证数据最终是有序,不缺失,无重复的
- tcp具备流量控制。接收端总是告知发送端自己一次能最大接受多少数据,这个叫通告窗口,通告窗口的大小动态变化。
流量控制是为了保证接收端的缓冲区不会溢出。(UDP不具有流量控制功能,当发送端发送速度过快,接受端接收速度慢是常见的) - tcp是全双工的,在任一时刻,任一端都可以既接收又发送(udp也是可以全双工的)
tcp连接的建立和终止
- 三路握手(总共需要3个分节)
- connect端发送SYN请求,包含自己的序号
- 服务端也发送自己的SYB序号,并且返回ACK,确认connect端的syn序号
- connect端返回ack,至此,双方都有了对方的序号。建立连接完成
-
四路挥手(总共需要4个分节)
- close的一端A是主动关闭的,因此它发送一个fin分节给对端B
- 对端B收到了fin,知道A不再有新数据要发送了,因此产生一个end-of-file,并发送ack代表自己收到了fin
- B可能还有数据传给A,等到B没有数据要发送给A了,它就也发送一个FIN给A
- A收到FIN后返回一个ACK给B,至此连接关闭
注意:不管是close()函数,还是主动或被动的结束进程,都会关闭描述符,因此在tcp层面都会发送一个fin
-
piggybacking:如果服务器处理请求的时间很短,那么可以将其返回的数据和请求ACK同时作为一个分节返回。
-
TCP发送一个分节的请求和一个分节的应答,总共需要8个分节,但是UDP只需要2个分组
-
为什么主动断开的一端需要TIME_WAIT时间为2 MSL(max segment length)?
- 防止最后一次ACK报文丢失。如果丢失,被动断开的一方会重发FIN报文,如果主动断开方已经关闭,就会产生错误
- 防止那些遗失的重复报文又出现。如果没有TIME_WAIT,客户端和服务端重建相同连接,遗失报文又出现了,就会导致数据混乱。
端口号
TCP, UDP, SCTP都使用16位端口号来区分进程,因此是unsigned short(2个字节)。
服务器使用众所周知的端口号,但客户端使用临时端口号。客户端无需在意临时端口号的具体值,只要该端口被唯一分配即可。
- IANA组织将端口号分为三类
- 众所周知端口 0-1023
- 已登记端口 1024-49151
- 私用端口 49152-65535(49152是65536的3/4)
IANA规定的众所周知端口(0-1023)在UNIX下面必须使用ROOT用户才可以使用,例如,FTP服务就只能用ROOT开启
套接字对
什么规定了一个TCP连接? 套接字对! (socket pair) <本地IP,本地端口,外地IP,外地端口>
TCP服务器必须根据套接字对才能决定要把接受到的分节送给哪个进程,而不能仅仅根据目的端口号。只要没有被匹配到的四元组,才会被送给监听套接字对应的进程。
- 一个很重要的点在于:TCP服务器是无法仅仅通过到达报文的目的端口号决定其要将报文送给哪个进程的,而是需要完整的四元组:(监听套接字和处理套接字占用同一个目的端口号)
缓冲区大小及限制
- 两个主机路径之间最小的MTU(maximum transmission unit)称之为路径MTU。两个方向的MTU可以不同,以太网的常见MTU位1500 BYTES
- 当一个IP数据报的大小超过链路的MTU时,IPv4和IPv6都会对报文进行分片。IPv4网络的发送主机和路由器都有可能分片,但是IPv6只有发送主机执行分片
- IPv4可以设置DF(don't fragment)位,如果该位被设置了,那么无论主机或者路由器都不会进行分片。当路由器接收到超出外出链路,但是又被设置了DF位的IP报文时,会返回ICMP报文。
- IPv6的转发路由器不进行分片,因此IPv6隐含了DF位。
- DF位可以用于路径MTU发现,设置DF位,并收到ICMP报文后,逐次地减小报文大小。
TCP输出
- write函数返回仅仅代表,进程的缓冲区复制到了内核的套接字缓冲区,代表我们可以重新使用进程缓冲区,但并不代表对端的TCP或者应用程序已经接受到了数据!
- 只有对端发过来ACK确认了,才能够从发送缓冲区里将数据丢弃
- TCP按照MSS(maximum segment size)的大小把块传给IP(MSS是对端通知的,如果没有通知,就使用最小缓冲区字节数576-40)
UDP输出
UDP协议没有内核发送缓冲区,但是有内核缓冲区。这两者有点不同,UDP的内核缓冲区,在发送完数据之后立即丢弃数据,但是内核发送缓冲区会保证收到ACK之后才丢弃数据。
UDP的write返回代表所写的数据报或者分片已经被加入到数据链路层的输出队列了
常见网络应用的协议栈
ping,traceroute: ICMP. 构造UDP报文发送,然后读取ICMP反馈
OSPF用原始IP,RIP用UDP,BGP用TCP
DNS在传输层既使用TCP,又使用UDP。
套接字地址结构
-
套接字地址结构仅仅在给定主机上使用,尽管ip,port会在主机间通信,但是结构本身不会在主机间传递。
-
内核需要struct sockaddr的原因是,无论什么样的地址,送入bind之后,都要取出sa_family字段确定结构的真实类型,然后再
进行指针转换,而sockaddr正定义了sa_family字段。但是从开发人员来看,这个参数定义为void*更方便,免去了强制转换的操作。 -
字节序需要程序员处理,但是位序的转换由网卡自动处理完成。网卡会根据主机的位序偏好进行位的转换
字节序转换函数
htons(16位), htonl(32位)
字节(内存)操纵函数
memset, memcpy, memcmp.都是处理字节的函数
地址处理函数(用于将字符串转化为网络字节序,或者相反)
inet_aton, inet_addr, inet_ntoa(注意该函数返回的字符串在静态区,该函数是不可重入的)
inet_pton, inet_ntop是新版的函数。inet_ntop是可重入的,也不会导致非法写内存
------------恢复内容结束------------