百战c++(网络)

Posted 兔老大RabbitMQ

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了百战c++(网络)相关的知识,希望对你有一定的参考价值。

杂记

  1. 底层向高层提供服务,下面的协议对上面的实体是透明的。
  2. MAC,网桥(可看做多接口的交换机)工作在数据链路层。路由器工作在网络层。
  3. 网络层向上只提供最简单灵活的,无连接的,尽最大努力交付的数据报服务
  4. ARP:IP->MAC 在局域网内广播ARP分组,设置生存时间(高速缓存)

 

MTU最大传输单元1500字节(数据+首部) 标志MF=1 表示后面还有MF=0.表示后面没有了。DF=0 表示可以分片,DF=1表示不可以分片。

片位移是相对位置即现在的数据报头在原来的哪个位置然后除以8.因为是以8字节为一个单位。

  1. 子网掩码作用:减少IP地址浪费。(不需要那么多主机数量)
  2. ICMP (差错报告/询问)报文。工作在IP层。IGMP该协议用来在ip主机和与其直接相邻的组播路由器之间建立、维护组播组成员关系。
  3. CIDR地址聚合:最长前缀匹配原则

子网划分 IP地址:: = <网络号>,<子网号>,<主机号>

分类 IP地址:: = <网络号>,<主机号>

Cidr地址聚合IP地址:: = <网络前缀>,<主机号>

OSI TCP/IP 五层model,各层都有什么硬件在工作

 

物理层设备:中继器,集线器。

数据链路层:网桥或交换机

网络层以上:网关

计算机网络上层调用下层服务,下层对上层来说是透明的。

浏览器输入一个地址回车之后都发生了啥?

浏览器中输入URL,首先浏览器要将URL解析为IP地址,首先检查本地hosts文件是否有这个映射关系。如果没有则要用到DNS协议,首先主机会查询DNS的缓存,如果没有就给本地DNS发送查询请求。

DNS查询分为两种方式,一种是递归查询,一种是迭代查询。如果是迭代查询,本地的DNS服务器,向根域名服务器发送查询请求,根域名服务器告知该域名的一级域名服务器,然后本地服务器给该一级域名服务器发送查询请求,然后依次类推直到查询到该域名的IP地址。DNS服务器是基于UDP的,因此会用到UDP协议。

递归查询是如果主机所询问的本地域名服务器不知道被查询的域名的IP地址,那么本地域名服务器就以DNS客户的身份向其它根域名服务器继续发出查询请求报文(即替主机继续查询),而不是让主机自己进行下一步查询。

得到IP地址后,浏览器就要与服务器建立一个http连接。http是建立在tcp上的无状态连接。(应用层)因此要用到http协议,http协议报文格式上面已经提到。http生成一个get请求报文,将该报文传给TCP层处理。如果采用https还会先对http数据进行加密。TCP层如果有需要先将HTTP数据包分片,分片依据路径MTU和MSS。TCP的数据包然后会发送给IP层,用到IP协议。IP层通过路由选路,一跳一跳发送到目的地址。当然在一个网段内的寻址是通过以太网协议实现(也可以是其他物理层协议,比如PPP,SLIP),以太网协议需要直到目的IP地址的物理地址,有需要ARP协议。

服务器处理请求,并返回html响应,浏览器接受请求的页面源码,浏览器渲染html,浏览器发送嵌入到html的对象请求,浏览器发送异步请求,关闭tcp连接。

TCP 和 UTP 有什么区别?

TCP面向连接(三次握手),通信前需要先建立连接;UDP面向无连接,通信前不需要连接。

TCP通过确认,序号、重传、流量控制、拥塞控制实现可靠传输;UDP不保障可靠传输,尽最大努力交付。

TCP面向字节流传输,因此可以被分割并在接收端重组;UDP面向数据报传输。

TCP点到点,UDP可以点到多点 udp可以使用同个套接字接受或发送一连串数据报

Tcp头部20字节,udp8字节

Tcp慢重量级协议,udp快轻量级协议。

三次握手

SYN

同步序号,表示此报文是一个连接请求报文或者连接接受报文

ACK

确认位,对接收到报文的确认

FIN

终止位,表示发送方完成数据发送,用来释放一个连接

RST

复位连接,表示tcp连接中出现严重错误。

PSH

推送位,尽可能快的将数据发送往接受进程

序列号seq:占4个字节,用来标记数据段的顺序,TCP把连接中发送的所有数据字节都编上一个序号,第一个字节的编号由本地随机产生;给字节编上序号后,就给每一个报文段指派一个序号;序列号seq就是这个报文段中的第一个字节的数据编号。

    确认号ack:占4个字节,期待收到对方下一个报文段的第一个数据字节的序号;序列号表示报文段携带数据的第一个字节的编号;而确认号指的是期望接收到下一个字节的编号;因此当前报文段最后一个字节的编号+1即为确认号。

    确认ACK:占1位,仅当ACK=1时,确认号字段才有效。ACK=0时,确认号无效

    同步SYN:连接建立时用于同步序号。当SYN=1,ACK=0时表示:这是一个连接请求报文段。若同意连接,则在响应报文段中使得SYN=1,ACK=1。因此,SYN=1表示这是一个连接请求,或连接接受报文。SYN这个标志位只有在TCP建产连接时才会被置1,握手完成后SYN标志位被置0。

终止FIN:用来释放一个连接。FIN=1表示:此报文段的发送方的数据已经发送完毕,并要求释放运输连接

PS:ACK、SYN和FIN这些大写的单词表示标志位,其值要么是1,要么是0;ack、seq小写的单词表示序号。

 

第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;

第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;

第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。

TCP为何采用三次握手,来建立连接,若采用二次握手可以吗。为什么采用四次挥手来释放连接。

不可以,采用三次握手是为了防止失效的连接请求报文段突然又传送到服务器,从而发生错误。由于客户端发送的连接请求报文段由于网络延迟等原因没有及时到达服务器,而客户端在等待一段时间后又重新向服务器发送连接请求,且建立成功,顺利完成数据传输。但是此时第一段报文到达服务器,若采用二次握手,服务器返会相应信息建立连接,但是此时客户端并不理会该链接,造成服务器资源浪费。

关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方将所有数据发送完毕,并不代表你所有的数据都发送给对方了,所以等自己数据发送完毕后,再发送FIN报文。针对每一个FIN报文,都需要一个ACK报文,所以共需要四次挥手。

           说网络建立连接之后是怎么关闭的,四次挥手

 

1)客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。

2)服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。

3)客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。

4)服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。

5)客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗MSL( 最长分节生命期)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。

6)服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。

出现大量TIME_WAIT的原因是,怎么解决

第四次挥手出现了丢包、超时。大量短连接(http 1.0默认使用短连接)导致的。

客户端程序中设置socket的SO_LINGER选项;

客户端机器增大tcp_max_tw_buckets的值;

修改ipv4.ip_local_port_range,增大可用端口范围,但只能缓解问题,不能根本解决问题;

改短连接为长链接(短连接数量太多)

socket api: close() 和 shutdown()

 对一条TCP连接而言,首先调用close()的一方会进入TIME_WAIT状态,除此之外,关于close()还有一些细节需要说明。
       对一个tcp socket调用close()的默认动作是将该socket标记为已关闭并立即返回到调用该api进程中。此时,从应用层来看,该socket fd不能再被进程使用,即不能再作为read或write的参数。然后才会发起TCP的4次挥手以彻底关闭TCP连接。
       调用close()是关闭TCP连接的正常方式,但这种方式存在两个限制,而这正是引入shutdown()的原因:
       1)close()其实只是将socket fd的引用计数减1,只有当该socket fd的引用计数减至0时,TCP传输层才会发起4次握手从而真正关闭连接。而shutdown则可以直接发起关闭连接所需的4次握手,而不用受到引用计数的限制;
       2)close()会终止TCP的双工链路。由于TCP连接的全双工特性,可能会存在这样的应用场景:local peer不会再向remote peer发送数据,而remote peer可能还有数据需要发送过来,在这种情况下,如果local peer想要通知remote peer自己不会再发送数据但还会继续收数据这个事实,用close()是不行的,而shutdown()可以完成这个任务。

TIME_WAIT状态是什么?进入TIME_WAIT状态等待2MSL主要有两个目的:

TIME_WAIT状态是主动关闭TCP连接的一方(即先发起FIN包的一方),在发送完最后一个ACK包后进入的状态。系统需要在TIME_WAIT状态下等待2MSL(maximum segment lifetime )后才能释放连接(端口)。根据RFC 793 MSL是2分钟,一般的TCP实现有30秒、1分钟和2分钟不等。

为实现TCP全双工连接的可靠释放。主动关闭连接的一方在对方没有收到最后一个ACK包时(这时对方还会重发FIN,收到两个FIN的时间间隔一定小于2MSL)有时间可以重发ACK包;

另一方面处于TIME_WAIT的连接(IP和端口组合)不能重用,这样可以保证被重新分配的socket不会受到之前残留的延迟重发报文影响。因为发送方的报文只能存活一个MSL,响应的也只能存活一个MSL。

如果已经建立了连接,但是客户端突然出现故障了怎么办?

TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接

端口只有65535个,怎么实现百万级并发

TCP服务器监听在指定端口接收客户端连接后,创建一个新的socket用于同客户端进行读写数据,但该socket并不需要也不会绑定一个新的端口,所以对于TCP服务器来说,不存在端口不够用的情况。

TCP连接标识符(fd 文件描述符)

src-ip src-port dest-ip dest-port protocol

TCP靠什么实现安全机制(差错控制机制)

序列号::数据到达接收方,接收方需要发送一个应答表示收到了该数据段,并且确认序号会说明下一次需要接受的序列号,2*RTT(报文段往返时间)+一个偏差值。

确认机制(累计机制)和超时重传。

流量控制

流量控制通过滑动窗口来实现。

解决了,网络之间数据不可靠的问题,例如丢包,重复包,出错,乱序,提高了吞吐率。

Tcp的滑动窗口不是固定大小的,而是由接收方通过tcp报文首部通告窗口字段向发送方通告它的窗口大小。

TCP会利用窗口控制来提高传输速度,意思是在一个窗口大小内,不用一定要等到应答才能发送下一段数据,窗口大小就是无需等待确认而可以继续发送数据的最大值。如果不使用窗口控制,每一个没收到确认应答的数据都要重发。

若超出时间没有收到ack,会重发之前没有确认的包(超时重传),发送方窗口后延不变。 若收到ack 则窗口后延前移,若通知窗口不变,则窗口前沿前移。若通知窗口缩小,则窗口前沿不移,或者移动减少。

若发送和接受缓冲区用完则回到起始序号重新开始计数。

拥塞控制

慢启动,快重传,快恢复。

Maxwindow=min(rwnd,cwnd)

Rwnd>cwnd; 可发送的数据量受网络拥塞控制

Rwnd<cwnd;可发送数据量受接受能力控制

慢启动:由小到大逐渐增大发送窗口,成倍增长,当达到慢启动阈值时(ssthresh),开始拥塞避免算法,每次加一。当出现数据传输超时时,cwnd重新设为1,ssthresh*=1/2。

开始发送方先设置cwnd(拥塞窗口)=1,发送第一个报文段M1,接收方接收到M1后,发送方接收到接收方的确认后,把cwnd增加到2,接着发送方发送M2M3,发送方接收到接收方发送的确认后cwnd增加到4,慢启动算法每经过一个传输轮次(认为发送方都成功接收接收方的确认),拥塞窗口cwnd就加倍。

快重传和快恢复。

快重传算法要求首先接收方收到一个失序的报文段后就立刻发出重复确认,而不要等待自己发送数据时才进行捎带确认。接收方成功的接受了发送方发送来的M1M2并且分别给发送了ACK,现在接收方没有收到M3,而接收到了M4,显然接收方不能确认M4,因为M4是失序的报文段。如果根据可靠性传输原理接收方什么都不做,但是按照快速重传算法,在收到M4M5等报文段的时候,不断重复的向发送方发送M2ACK,如果接收方一连收到三个重复的ACK,那么发送方不必等待重传计时器到期,由发送方尽早重传未被确认的报文段。

快恢复(拥塞避免)

  1. 当发送发连续接收到三个确认时,就执行乘法减小算法,把慢启动开始门限(ssthresh)减半,但是接下来并不执行慢开始算法。
  2. 此时不执行慢启动算法,而是把cwnd设置为ssthresh的一半, 然后执行拥塞避免算法,使拥塞窗口缓慢增大。

请你说一说TCP/IP数据链路层的交互过程(ARP)

网络层等到数据链层用mac地址作为通信目标,数据包到达网络等准备往数据链层发送的时候,首先会去自己的arp缓存表(存着ip-mac对应关系)去查找改目标ipmac地址,如果查到了,就讲目标ipmac地址封装到链路层数据包的包头。如果缓存中没有找到,会发起一个广播:who is ip XXX tell ip XXX,所有收到的广播的机器看这个ip是不是自己的,如果是自己的,则以单拨的形式将自己的mac地址回复给请求的机器

以上是关于百战c++(网络)的主要内容,如果未能解决你的问题,请参考以下文章

百战c++(网络)

百战c++

百战c++

百战c++

百战c++(数据库2)

百战c++(数据库2)