您的位置:首页 > 理论基础 > 计算机网络

网络编程问题

2015-10-21 21:45 726 查看
1:tcp和udp的区别

tcp有连接,有验证重发机制,能保证通信可靠性
udp无连接,存在丢包、错包、乱序现象,但开销小

2:流量控制和拥塞控制的实现机制

TCP的流量控制

1.概述

     所谓的流量控制就是让发送方的发送速率不要太快,让接收方来得及接受。利用滑动窗口机制可以很方便的在TCP连接上实现对发送方的流量控制。TCP的窗口单位是字节,不是报文段,发送方的发送窗口不能超过接收方给出的接收窗口的数值。



     如图所示,说明了利用可变窗口大小进行流量控制。设主机A向主机B发送数据。双方确定的窗口值是400.再设每一个报文段为100字节长,序号的初始值为seq=1,图中的箭头上面大写ACK,表示首部中的却认为为ACK,小写ack表示确认字段的值。

     接收方的主机B进行了三次流量控制。第一次把窗口设置为rwind=300,第二次减小到rwind=100最后减到rwind=0,即不允许发送方再发送过数据了。这种使发送方暂停发送的状态将持续到主机B重新发出一个新的窗口值为止。

     假如,B向A发送了零窗口的报文段后不久,B的接收缓存又有了一些存储空间。于是B向A发送了rwind=400的报文段,然而这个报文段在传送中丢失了。A一直等待收到B发送的非零窗口的通知,而B也一直等待A发送的数据。这样就死锁了。为了解决这种死锁状态,TCP为每个连接设有一个持续计时器。只要TCP连接的一方收到对方的零窗口通知,就启动持续计时器,若持续计时器
4000
设置的时间到期,就发送一个零窗口探测报文段(仅携带1字节的数据),而对方就在确认这个探测报文段时给出了现在的窗口值。

2.TCP报文段发送时机的选择

     TCP豹纹短短发送时机主要有以下几种选择途径。

     1)TCP维持一个变量,它等于最大报文段长度MSS,只要缓存中存放的数据达到MSS字节就组装成一个TCP报文段发送出去。

     2)由发送方的应用程序指明要求发送报文段,即TCP支持的推送操作

     3)是发送方的一个计时器期限到了,这时就把当前已有的缓存数据装入报文段发送出去。

TCP的拥塞控制
1.拥塞控制的原理

     在某段时间,若对网络中的某一资源的需求超过了该资源所能提供的可用部分,网络的性能就要变化,这种情况叫做拥塞。

     网络拥塞往往是由许多因素引起的,简单的提高节点处理机的速度或者扩大结点缓存的存储空间并不能解决拥塞问题。例如

          1)当某个结点缓存容量扩展到非常大,于是凡到达该结点的分组均可在结点的缓存队列中排队,不受任何限制。由于输出链路的容量和处理机的速度并未提高,因此在这队列中的绝大多数的分组在排队等待时间会大大增加,结果上层软件只好把他们进行重传。

     因此,问题的是指往往是整个系统的各个部分不匹配,只有各个部分平衡了,问题才会得到解决。

2.拥塞控制和流量控制的差别

     所谓拥塞控制就是防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。拥塞控制所要做的都有一个前提,就是网络能承受现有的网络负荷。

     流量控制往往指的是点对点通信量的控制,是个端到端的问题。流量控制所要做的就是控制发送端发送数据的速率,以便使接收端来得及接受。

3.拥塞控制设计

     拥塞控制是很难设计的,因为它是一个动态的问题,许多情况下,甚至正式拥塞控制机制本身成为引起网络性能恶化甚至死锁的原因。从控制理论的角度来看拥塞控制这个问题,可以分为开环控制和闭环控制两种方法。开环控制就是在设计网络时事先将有关拥塞发生的所有因素考虑周到,一旦系统运行起来就不能在中途改正。

     闭环控制是基于反馈环路的概念,包括如下措施:

     1)监测网路系统以便检测拥塞在何时何地发生

     2)把拥塞发生的信息传送到可采取行动的地方

     3)调整网络系统的行动以解决出现的问题。

4.拥塞控制方法

因特网建议标准RFC2581定义了进行拥塞控制的四种算法,即慢开始(Slow-start),拥塞避免(Congestion Avoidance)快重传(Fast Restrangsmit)和快回复(Fast Recovery)。我们假定

     1)数据是单方向传送,而另外一个方向只传送确认

     2)接收方总是有足够大的缓存空间,因为发送窗口的大小由网络的拥塞程度来决定。

 

--慢开始和拥塞避免

     发送报文段速率的确定,既要根据接收端的接收能力,又要从全局考虑不要使网络发生拥塞,这由接收窗口和拥塞窗口两个状态量确定。接收端窗口(Reciver Window)又称通知窗口(Advertised Window),是接收端根据目前的接收缓存大小所许诺的最新窗口值,是来自接收端的流量控制。拥塞窗口cwnd(Congestion Window)是发送端根据自己估计的网络拥塞程度而设置的窗口值,是来自发送端的流量控制。

     慢启动原理:

     1)当主机开始发送数据时,如果立即将较大的发送窗口的全部数据字节都注入到网络中,那么由于不清楚网络的情况,有可能引其网络拥塞

     2)比较好的方法是试探一下,即从小到达逐渐增大发送端的拥塞控制窗口数值

     3)通常在刚刚开始发送报文段时可先将拥塞窗口cwnd设置为一个最大报文段的MSS的数值。在每收到一个对新报文段确认后,将拥塞窗口增加至多一个MSS的数值,当rwind足够大的时候,为了防止拥塞窗口cwind的增长引起网络拥塞,还需要另外一个变量---慢开始门限ssthresh

     拥塞控制具体过程为:

     1)TCP连接初始化,将拥塞窗口设置为1

     2)执行慢开始算法,cwind按指数规律增长,知道cwind == ssthress开始执行拥塞避免算法,cwnd按线性规律增长

     3)当网络发生拥塞,把ssthresh值更新为拥塞前ssthresh值的一半,cwnd重新设置为1,按照步骤(2)执行。

--快重传和快恢复

     一条TCP连接有时会因等待重传计时器的超时而空闲较长的时间,慢开始和拥塞避免无法很好的解决这类问题,因此提出了快重传和快恢复的拥塞控制方法。

     快重传算法并非取消了重传机制,只是在某些情况下更早的重传丢失的报文段(如果当发送端接收到三个重复的确认ACK时,则断定分组丢失,立即重传丢失的报文段,而不必等待重传计时器超时)。慢开始算法只是在TCP建立时才使用

     快恢复算法有以下两个要点:

     1)当发送方连续收到三个重复确认时,就执行“乘法减小”算法,把慢开始门限减半,这是为了预防网络发生拥塞。

     2)由于发送方现在认为网络很可能没有发生拥塞,因此现在不执行慢开始算法,而是把cwnd值设置为慢开始门限减半后的值,然后开始执行拥塞避免算法,是拥塞窗口的线性增大。

3:滑动窗口的实现机制

ARQ与滑动窗口概念

       滑动窗口协议,是TCP使用的一种流量控制方法。该协议允许发送方在停止并等待确认前可以连续发送多个分组。由于发送方不必每发一个分组就停下来等待确认,因此该协议可以加速数据的传输。

   自动重传请求(Automatic
Repeat-reQuest,ARQ)是OSI模型中数据链路层的错误纠正协议之一。它通过使用确认和超时这两个机制,在不可靠服务的基础上实现可靠的信息传输。如果发送方在发送后一段时间之内没有收到确认帧,它通常会重新发送。ARQ可能包括停止等待ARQ协议、回退ARQ和连续ARQ协议,错误检测(Error
Detection)、正面确认(Positive Acknowledgment)、超时重传(Retransmission after Timeout)和 负面确认及重传(Negative Acknowledgment and Retransmission)等机制。

他们的概念是差不多的只是作用于不同的网络层。数据链路层的滑动窗口是“个数固定”的。而TCP的滑动窗口是“个数可变”的,可以由接收端设置WIN字段来修改。

         传统自动重传请求分成为三种,即停等式(stop-and-wait)ARQ,回退n帧(go-back-n)ARQ,以及选择性重传(selective repeat)ARQ。后两种协议是滑动窗口技术与请求重发技术的结合,由于窗口尺寸开到足够大时,帧在线路上可以连续地流动,因此又称其为连续ARQ协议。三者的区别在于对于出错的数据报文的处理机制不同。三种ARQ协议中,复杂性递增,效率也递增。除了传统的ARQ,还有混合ARQ(Hybrid-ARQ)。

  当发送窗口和接收窗口的大小都等于 1时,就是停止等待协议。

 

  当发送窗口大于1,接收窗口等于1时,就是回退N步协议。

  当发送窗口和接收窗口的大小均大于1时,就是选择重发协议

停止并等待ARQ协议(stop-and-wait)

     停止并等待协议的工作原理如下:
发送点对接收点发送数据包,然后等待接收点回复ACK并且开始计时。
在等待过程中,发送点停止发送新的数据包。
当数据包没有成功被接收点接收时候,接收点不会发送ACK. 这样发送点在等待一定时间后,重新发送数据包。
反复以上步骤直到收到从接收点发送的ACK.

    发送点的等待时间应当至少大于传输点数据包发送时间(数据包容量除以发送点传输速度),接收点ACK接收时间(ACK容量除以接收点传输速度),数据在连接上的传送时间,接收点检验接收数据是否正确的时间之和。在实际应用当中,等待时间是这个和的2到3倍。

    这个协议的缺点是较长的等待时间导致低的数据传输速度。在低速传输时,对连接频道的利用率比较好,但是在高速传输时,频道的利用率会显著下降。

          


 


回退n帧的ARQ

  在回退n帧的ARQ中,当发送方接收到接收方的状态报告指示报文出错后,发送方将重传过去的n个报文。  回退N,发送窗口大于1,接收窗口等于1。允许发送方可以连续发送信息帧,但是,一旦某帧发生错误,必须重新发送该帧及其后的n帧。这种方式提高了信道的利用率,但允许已发送有待于确认的帧越多,可能要退回来重发的帧也越多。

回退的基本原理图:

     


如果当前发送的是数据链路层上的最后一个帧(无论是数据帧还是确认帧),但不幸的是该帧出错或丢失了,此种情况也适用于中间某一帧开始的所有后继帧全部出错或丢失的情况(同样可以是数据帧或确认帧),那么发送端会一直等待下去,而且接收端对此也毫无察觉。

为了解决这个问题,需要采用超时机制。可以有多种定时方案,在早期方案中采用的一种是独立的定时器,发送端每发送一个数据帧就启动一次,当收到确认帧后,定时器复位;如果直到超时还没有收到确认帧,则重发该帧以及后继的帧。

其原理如图下所示:

  


连续ARQ协议(Continuous ARQ)

     为了克服停止并等待ARQ协议长时间等待ACK的缺点。这个协议会连续发送一组数据包,然后再等待这些数据包的ACK.

连续 ARQ 协议的工作原理图:

      


    如图所示,结点 A 向结点 B 发送数据帧。当结点 A 发完 0 号帧后,不是停止等待,而是继续发送后续的 1 号帧、2 号帧等。由于连续发送了许多帧,所以应答帧不仅要说明是对哪一帧进行确认或否认,而且应答帧本身也必须编号。
    结点 B 正确地收到了 0 号帧和 1 号帧,并送交其主机。现在设 2 号帧出了差错,于是结点 B 就将有差错的 2 号帧丢弃。结点 B 运行的协议可以有两种选择:一种是在出现差错时就向结点 A 发送否认帧,另一种则是在出现差错时不做任何响应。我们现在假定采用后一种协议,这种协议比较简单,使用得较多。


  选择重传
(Selective Repeat)

发送点连续发送数据包但对每个数据包都设有个一个计时器。
当在一定时间内没有收到某个数据包的ACK时,发送点只重新发送那个没有ACK的数据包

  这个方法的缺点是接收点收到的数据包的顺序可能不是发送的数据包顺序。因此在数据包里必须含有顺序字符来帮助接受点来排序。
接收点丢弃从第一个没有收到的数据包开始的所有数据包。
发送点收到NACK后,从NACK中指明的数据包开始重新发送

  这个办法的问题是如何正确选择表明数据包的顺序字符的数量。这个数量因当包括ACK或者ACK从接收点到达发送点的时间。

                                        


滑动窗口

        TCP滑动窗口用来暂存两台计算机间要传送的数据分组。每台运行TCP协议的计算机有两个滑动窗口:一个用于数据发送,另一个用于数据接收。发送端待发数据分组在缓冲区排队等待送出。被滑动窗口框入的分组,是可以在未收到接收确认的情况下最多送出的部分。滑动窗口左端标志X的分组,是已经被接收端确认收到的分组。随着新的确认到来,窗口不断向右滑动。

       TCP协议软件依靠滑动窗口机制解决传输效率和流量控制问题。它可以在收到确认信息之前发送多个数据分组。这种机制使得网络通信处于忙碌状态,提高了整个网络的吞吐率,它还解决了端到端的通信流量控制问题,允许接收端在拥有容纳足够数据的缓冲之前对传输进行限制。在实际运行中,TCP滑动窗口的大小是可以随时调整的。收发端TCP协议软件在进行分组确认通信时,还交换滑动窗口控制信息,使得双方滑动窗口大小可以根据需要动态变化,达到在提高数据传输效率的同时,防止拥塞的发生。

      称窗口左边沿向右边沿靠近为窗口合拢,这种现象发生在数据被发送和确认时。当窗口右边沿向右移动时将允许发送更多的数据,称之为窗口张开。这种现象发生在另一端的接收进程读取已经确认的数据并释放了TCP的接收缓存时。

      当右边沿向左移动时,称为窗口收缩。Host Requirements RFC强烈建议不要使用这种方式。但TCP必须能够在某一端产生这种情况时进行处理。 如果左边沿到达右边沿,则称其为一个零窗口。

   滑动窗口原理图:

                                    


 

      在这个图中,我们将字节从1至11进行标号。接收方通告的窗口称为提出的窗口,它覆盖了从第4字节到第9字节的区域,表明接收方已经确认了包括第3字节在内的数据,且通告窗口大小为6。我们知道窗口大小是与确认序号相对应的。发送方计算它的可用窗口,该窗口表明多少数据可以立即被发送。当接收方确认数据后,这个滑动窗口不时地向右移动。窗口两个边沿的相对运动增加或减少了窗口的大小。我们使用三个术语来描述窗口左右边沿的运动:

称窗口左边沿向右边沿靠近为窗口合拢。这种现象发生在数据被发送和确认时。 

当窗口右边沿向右移动时将允许发送更多的数据,我们称之为窗口张开。这种现象发生在另一端的接收进程读取已经确认的数据并释放了T C P的接收缓存时。 

当右边缘向左移动时,称之为窗口收缩。

滑动窗口流量控制管理:
      1、流量控制是管理两端的流量,以免会产生发送过块导致收端溢出,或者因收端处理太快而浪费时间的状态。用的是:滑动窗口,以字节为单位
     

      2、窗口有3种动作:展开(右边向右),合拢(左边向右),收缩(右边向左)这三种动作受接收端的控制。
                 合拢:表示已经收到相应字节的确认了
                 展开:表示允许缓存发送更多的字节
                 收缩(非常不希望出现的,某些实现是禁止的):表示本来可以发送的,现在不能发送;但是如果收缩的是那些已经发出的,就会有问题;为了避免,收端会等待到缓存中有更多缓存空间时才进行通信。
      发端窗口的大小取决于收端的窗口大小rwnd(TCP报文的窗口大小字段)和拥塞窗口大小cwnd(见拥塞控制)
发端窗口大小 = min{ rwnd , cwnd };
        3、关闭窗口:窗口缩回有个例外,就是发送rwnd=0表示暂时不愿意接收数据。这种情况下,发端不是把窗口收缩,二是停止发送数据。(为了比避免死锁,会用一些探测报定时发送试探,见定时器一节)

      4、问题:某些时候,由于发端或收端的数据很慢,会引起大量的1字节数据痛惜,浪费很多资源。
        (1)、发端的进程产生数据很慢时候,时不时的来个1字节数据,那么TCP就会1字节1字节的发送,效率很低。
      解决方法(Nagle算法):
        a、将第一块数据发出去
        b、然后等到发送缓存有足够多的数据(最大报文段长度),或者等到收端确认的ACK时再发送数据。
        c、重复b的过程
       (2)、收端进程由于消耗数据很慢,所以可能会有这么一种情况,收端会发送其窗口大小为1的信息,然后有是1字节的传输
      解决办法(2种)
        a、Clark方法:在接收缓存的一半变空,或者有足够空间放最大报文长度之前,宣告接收窗口大小为0
        b、推迟确认:在对收到的报文段确认之前等待到足够的接收缓存,或者等待到一个时间段

4:多线程如何同步。

1.Critical Section
  临界区
A.速度快
B.不能用于不同进程
C.不能进行资源统计(每次只可以有一个线程对共享资源进行存取)


临界区是一种轻量级机制,在某一时间内只允许一个线程执行某个给定代码段。通常在修改全局数据(如集合类)时会使用临界区。事件、多用户终端执行程序和信号量也用于多线程同步,但临界区与它们不同,它并不总是执行向内核模式的控制转换,这一转换成本昂贵。稍后将会看到,要获得一个未占用临界区,事实上只需要对内存做出很少的修改,其速度非常快。只有在尝试获得已占用临界区时,它才会跳至内核模式。这一轻量级特性的缺点在于临界区只能用于对同一进程内的线程进行同步。

2.Mutex  互斥锁
A.速度慢
B.可用于不同进程
C.不能进行资源统计


对共享资源的访问,
要对互斥量进行加锁, 如果互斥量已经上了锁, 调用线程会阻塞, 直到互斥量被解锁. 在完成了对共享资源的访问后, 要对互斥量进行解锁.


锁类型  初始化方式    
                                    加解锁特征                              调度特征


普通锁  PTHREAD_MUTEX_INITIALIZER    
同一线程可重复加锁,解锁一次释放锁     先等待锁的进程先获得锁


嵌套锁  
PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP    同一线程可重复加锁,解锁同样次数才可释放锁    先等待锁的进程先获得锁
纠错锁   PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP   同一线程不能重复加锁,加上的锁只能由本线程解锁  先等待锁的进程先获得锁
自适应锁 PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP     同一线程可重加锁,解锁一次生效      所有等待锁的线程自由竞争 




3.Semaphore
 信号灯
A.速度慢
B.可用于不同进程
C.可进行资源统计(可以让一个或超过一个线程对共享资源进行存取)


它负责协调各个线程,
以保证它们能够正确、合理的使用公共资源。




信号灯其实就是一个计数器,也是一个整数。每一次调用wait操作将会使semaphore值减一,而如果semaphore值已经为0,则wait操作将会阻塞。每一次调用post操作将会使semaphore值加一。将这些操作用到上面的问题中。工作线程每一次调用wait操作,如果此时链表中没有节点,则工作线程将会阻塞,直到链表中有节点。生产者线程在每次往链表中添加节点后调用post操作,信号灯值会加一。这样阻塞的工作线程就会停止阻塞,继续往下执行。

信号灯的类型为sem_t。在声明后必须调用sem_init()。需要传递两个参数,第一个参数就是你之前声明的sem_t变量,第二个必须为0。当你不再需要信号灯时,你必须调用sem_destroy()来释放资源。

等待信号灯的操作为sem_wait()。投递一个信号的操作为sem_wait()。和互斥量一样,等待信号灯也有一个非阻塞的操作,sem_trywait()。该操作在没有信号灯的时候返回EAGAIN。


4.Event   事件
A.速度慢
B.可用于不同进程
C.可进行资源统计


在所有的内核对象中,事件内核对象是个最基本的。它包含一个使用计数(与所有内核对象一样),一个BOOL值(用于指明该事件是个自动重置的事件还是一个人工重置的事件),还有一个BOOL值(用于指明该事件处于已通知状态还是未通知状态)。事件能够通知一个线程的操作已经完成。有两种类型的事件对象。一种是人工重置事件,另一种是自动重置事件。他们不同的地方在于:当人工重置的事件得到通知时,等待该事件的所有线程均变为可调度线程。当一个自动重置的事件得到通知时,等待该事件的线程中只有一个线程变为可调度线程。




5:进程间通讯的方式有哪些,各有什么优缺点

进程通信的含义

进程是转入内存并准备执行的程序,每个程序都有私有的虚拟地址空间,由代码,数据以及它可利用的系统资源(如文件,管道)组成.多进程/多线程是windows操作系统的一个基本特征.Linux系统一般都统称为进程.

由于不同的进程运行在各自不同的内存空间中,其中一个进程对于变量的修改另一方是无法感知的,因此,进程之间的消息传递不能通过变量或其他数据结构直接进行,只能通过进程间通信来完成.进程间通信是指不同进程间进行数据共享和数据交换.

进程通信的分类

根据进程通信时信息量大小的不同,可以将进程通信划分为两大类型:控制信息的通信(低级通信)和大批数据信息的通信(高级通信).

低级通信主要用于进程之间的同步,互斥,终止和挂起等等控制信息的传递.

高级通信主要用于进程间数据块数据的交换和共享,常见的高级通信有管道,消息队列,共享内存等.

进程通信的方式

1)文件和记录锁定

为避免两个进程间同时要求访问同一资源而引起访问和操作的混乱,在进程对共享资源进行访问前必须对其锁定,该进程访问完后再释放.这是UNIX为共享资源提供的互斥性保障.

2)管道

管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用.进程的亲缘关系一般指的是父子关系.管道一般用于两个不同进程之间的通信.当一个进程创建了一个管道,并调用fork创建自己的一个子进程后,父进程关闭读管道端,子进程关闭写管道端,这样提供了两个进程之间数据流动的一种方式.

3)有名管道

有名管道也是一种半双工的通信方式,但是它允许无亲缘关系进程间的通信.

4)FIFO

FIFO是一种先进先出的队列.它类似于一个管道,只允许数据的单向流动.每个FIFO都有一个名字,允许你不相关的进程访问同一个FIFO,因此也成为命名管.

5)信号量

信号量是一个计数器,可以用来控制多个线程对共享资源的访问.,它不是用于交换大批数据,而用于多线程之间的同步.它常作为一种锁机制,防止某进程在访问资源时其它进程也访问该资源.因此,主要作为进程间以及同一个进程内不同线程之间的同步手段.

6)信号

信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生.

7)消息队列

消息队列是消息的链表,存放在内核中并由消息队列标识符标识.消息队列克服了信号传递信息少,管道只能承载无格式字节流以及缓冲区大小受限等特点.消息队列是UNIX下不同进程之间可实现共享资源的一种机制,UNIX允许不同进程将格式化的数据流以消息队列形式发送给任意进程.对消息队列具有操作权限的进程都可以使用msget完成对消息队列的操作控制.通过使用消息类型,进程可以按任何顺序读信息,或为消息安排优先级顺序.

8)共享内存

共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问.共享内存是最快的IPC(进程间通信)方式,它是针对其它进程间通信方式运行效率低而专门设计的.它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步与通信.

9)套接字(socket)

套接口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同进程及其间进程的通信.

通信方式的优缺点

几种通信方法总结综上所述.进程之间的多种通信方法各自有各自的优点和缺点:如果用户传递的信息较少.或是需要通过信号来触发某些行为.前文提到的软中断信号机制不失为一种简捷有效的进程间通信方式.但若是进程间要求传递的信息量比较大或者进程间存在交换数据的要求,那就需要考虑别的通信方式了。无名管道简单方便.但局限于单向通信的工作方式.并且只能在创建它的进程及其子孙进程之间实现管道的共享:有名管道虽然可以提供给任意关系的进程使用.但是由于其长期存在于系统之中,使用不当容易出错.所以普通用户一般不建议使用。消息缓冲可以不再局限于父子进程.而允许任意进程通过共享消息队列来实现进程间通信.并由系统调用函数来实现消息发送和接收之间的同步.从而使得用户在使用消息缓冲进行通信时不再需要考虑同步问题.使用方便,但是消息队列中信息的复制需要额外消耗CPU的时间.不适宜于信息量大或操作频繁的场合。共享内存针对消息缓冲的缺点改而利用内存缓冲区直接交换信息,无须复制,快捷、信息量大是其优点。但是共享内存的通信方式是通过将共享的内存缓冲区直接附加到进程的虚拟地址空间中来实现的.因此,这些进程之间的读写操作的同步问题操作系统无法实现。必须由各进程利用其他同步工具解决。另外,由于内存实体存在于计算机系统中.所以只能由处于同一个计算机系统中的诸进程共享,不方便网络通信。不同的进程通信方式有不同的优点和缺点.因此.对于不同的应用问题,要根据问题本身的情况来选择进程间的通信方式。

一般来说,进程间的通信根据通信内容可以划分为两种:即控制信息的传送与大批数据传送。有时也把进程间控制信息的交换称为低级通信,而把进程间大批量数据的交换称为高级通信。
6:tcp连接建立的时候3次握手的具体过程,以及其中的每一步是为什么

1)客户端发送一个带SYN标志的TCP报文到服务器。这是三次握手过程中的报文1。
(2) 服务器端回应客户端的,这是三次握手中的第2个报文,这个报文同时带ACK标志和SYN标志。因此它表示对刚才客户端SYN报文的回应;同时又标志SYN给客户端,询问客户端是否准备好进行数据通讯。
(3) 客户必须再次回应服务段一个ACK报文,这是报文段3。

7:tcp断开连接的具体过程,其中每一步是为什么那么做

由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个
FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
 (1) TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送(报文段4)。
 (2) 服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1(报文段5)。和SYN一样,一个FIN将占用一个序号。
 (3) 服务器关闭客户端的连接,发送一个FIN给客户端(报文段6)。
 (4) 客户段发回ACK报文确认,并将确认序号设置为收到序号加1(报文段7)。




8:tcp建立连接和断开连接的各种过程中的状态转换细节

CLOSED: 这个没什么好说的了,表示初始状态。
LISTEN: 这个也是非常容易理解的一个状态,表示服务器端的某个SOCKET处于监听状态,可以接受连接了。
SYN_RCVD: 这个状态表示接受到了SYN报文,在正常情况下,这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂,基本上用netstat你是很难看到这种状态的,除非你特意写了一个客户端测试程序,故意将三次TCP握手过程中最后一个ACK报文不予发送。因此这种状态时,当收到客户端的ACK报文后,它会进入到ESTABLISHED状态。
SYN_SENT: 这个状态与SYN_RCVD遥想呼应,当客户端SOCKET执行CONNECT连接时,它首先发送SYN报文,因此也随即它会进入到了SYN_SENT状态,并等待服务端的发送三次握手中的第2个报文。SYN_SENT状态表示客户端已发送SYN报文。
ESTABLISHED:这个容易理解了,表示连接已经建立了。
FIN_WAIT_1: 这个状态要好好解释一下,其实FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即进入到FIN_WAIT_1状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应ACK报文,所以FIN_WAIT_1状态一般是比较难见到的,而FIN_WAIT_2状态还有时常常可以用netstat看到。
FIN_WAIT_2:上面已经详细解释了这种状态,实际上FIN_WAIT_2状态下的SOCKET,表示半连接,也即有一方要求close连接,但另外还告诉对方,我暂时还有点数据需要传送给你,稍后再关闭连接。
TIME_WAIT: 表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了。如果FIN_WAIT_1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。
CLOSING: 这种状态比较特殊,实际情况中应该是很少见,属于一种比较罕见的例外状态。正常情况下,当你发送FIN报文后,按理来说是应该先收到(或同时收到)对方的ACK报文,再收到对方的FIN报文。但是CLOSING状态表示你发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN报文。什么情况下会出现此种情况呢?其实细想一下,也不难得出结论:那就是如果双方几乎在同时close一个SOCKET的话,那么就出现了双方同时发送FIN报文的情况,也即会出现CLOSING状态,表示双方都正在关闭SOCKET连接。
CLOSE_WAIT: 这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN报文给自己,你系统毫无疑问地会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正需要考虑的事情是察看你是否还有数据发送给对方,如果没有的话,那么你也就可以close这个SOCKET,发送FIN报文给对方,也即关闭连接。所以你在CLOSE_WAIT状态下,需要完成的事情是等待你去关闭连接。
LAST_ACK: 这个状态还是比较容易好理解的,它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也即可以进入到CLOSED可用状态了。
最后有2个问题的回答,我自己分析后的结论(不一定保证100%正确)
1、 为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?
这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可以未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。
2、 为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态?
这是因为:虽然双方都同意关闭连接了,而且握手的4个报文也都协调和发送完毕,按理可以直接回到CLOSED状态(就好比从SYN_SEND状态到ESTABLISH状态那样);但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的ACK报文会一定被对方收到,因此对方处于LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文。


9:epool与select的区别

elect、poll、epoll之间的区别总结[整理]

  select,poll,epoll都是IO多路复用的机制。I/O多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。但select,poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间。关于这三种IO多路复用的用法,前面三篇总结写的很清楚,并用服务器回射echo程序进行了测试。连接如下所示:
select:http://www.cnblogs.com/Anker/archive/2013/08/14/3258674.html
poll:http://www.cnblogs.com/Anker/archive/2013/08/15/3261006.html
epoll:http://www.cnblogs.com/Anker/archive/2013/08/17/3263780.html
  今天对这三种IO多路复用进行对比,参考网上和书上面的资料,整理如下:
1、select实现
select的调用过程如下所示:



(1)使用copy_from_user从用户空间拷贝fd_set到内核空间
(2)注册回调函数__pollwait
(3)遍历所有fd,调用其对应的poll方法(对于socket,这个poll方法是sock_poll,sock_poll根据情况会调用到tcp_poll,udp_poll或者datagram_poll)
(4)以tcp_poll为例,其核心实现就是__pollwait,也就是上面注册的回调函数。
(5)__pollwait的主要工作就是把current(当前进程)挂到设备的等待队列中,不同的设备有不同的等待队列,对于tcp_poll来说,其等待队列是sk->sk_sleep(注意把进程挂到等待队列中并不代表进程已经睡眠了)。在设备收到一条消息(网络设备)或填写完文件数据(磁盘设备)后,会唤醒设备等待队列上睡眠的进程,这时current便被唤醒了。
(6)poll方法返回时会返回一个描述读写操作是否就绪的mask掩码,根据这个mask掩码给fd_set赋值。
(7)如果遍历完所有的fd,还没有返回一个可读写的mask掩码,则会调用schedule_timeout是调用select的进程(也就是current)进入睡眠。当设备驱动发生自身资源可读写后,会唤醒其等待队列上睡眠的进程。如果超过一定的超时时间(schedule_timeout指定),还是没人唤醒,则调用select的进程会重新被唤醒获得CPU,进而重新遍历fd,判断有没有就绪的fd。
(8)把fd_set从内核空间拷贝到用户空间。
总结:
select的几大缺点:
(1)每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大
(2)同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大
(3)select支持的文件描述符数量太小了,默认是1024
2 poll实现
  poll的实现和select非常相似,只是描述fd集合的方式不同,poll使用pollfd结构而不是select的fd_set结构,其他的都差不多。
关于select和poll的实现分析,可以参考下面几篇博文:
http://blog.csdn.net/lizhiguo0532/article/details/6568964#comments
http://blog.csdn.net/lizhiguo0532/article/details/6568968
http://blog.csdn.net/lizhiguo0532/article/details/6568969
http://www.ibm.com/developerworks/cn/linux/l-cn-edntwk/index.html?ca=drs-
http://linux.chinaunix.net/techdoc/net/2009/05/03/1109887.shtml
3、epoll
  epoll既然是对select和poll的改进,就应该能避免上述的三个缺点。那epoll都是怎么解决的呢?在此之前,我们先看一下epoll和select和poll的调用接口上的不同,select和poll都只提供了一个函数——select或者poll函数。而epoll提供了三个函数,epoll_create,epoll_ctl和epoll_wait,epoll_create是创建一个epoll句柄;epoll_ctl是注册要监听的事件类型;epoll_wait则是等待事件的产生。
  对于第一个缺点,epoll的解决方案在epoll_ctl函数中。每次注册新的事件到epoll句柄中时(在epoll_ctl中指定EPOLL_CTL_ADD),会把所有的fd拷贝进内核,而不是在epoll_wait的时候重复拷贝。epoll保证了每个fd在整个过程中只会拷贝一次。
  对于第二个缺点,epoll的解决方案不像select或poll一样每次都把current轮流加入fd对应的设备等待队列中,而只在epoll_ctl时把current挂一遍(这一遍必不可少)并为每个fd指定一个回调函数,当设备就绪,唤醒等待队列上的等待者时,就会调用这个回调函数,而这个回调函数会把就绪的fd加入一个就绪链表)。epoll_wait的工作实际上就是在这个就绪链表中查看有没有就绪的fd(利用schedule_timeout()实现睡一会,判断一会的效果,和select实现中的第7步是类似的)。
  对于第三个缺点,epoll没有这个限制,它所支持的FD上限是最大可以打开文件的数目,这个数字一般远大于2048,举个例子,在1GB内存的机器上大约是10万左右,具体数目可以cat /proc/sys/fs/file-max察看,一般来说这个数目和系统内存关系很大。
总结:
(1)select,poll实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替。而epoll其实也需要调用epoll_wait不断轮询就绪链表,期间也可能多次睡眠和唤醒交替,但是它是设备就绪时,调用回调函数,把就绪fd放入就绪链表中,并唤醒在epoll_wait中进入睡眠的进程。虽然都要睡眠和交替,但是select和poll在“醒着”的时候要遍历整个fd集合,而epoll在“醒着”的时候只要判断一下就绪链表是否为空就行了,这节省了大量的CPU时间。这就是回调机制带来的性能提升。
(2)select,poll每次调用都要把fd集合从用户态往内核态拷贝一次,并且要把current往设备等待队列中挂一次,而epoll只要一次拷贝,而且把current往等待队列上挂也只挂一次(在epoll_wait的开始,注意这里的等待队列并不是设备等待队列,只是一个epoll内部定义的等待队列)。这也能节省不少的开销。
参考资料:
http://www.cnblogs.com/apprentice89/archive/2013/05/09/3070051.html
http://www.linuxidc.com/Linux/2012-05/59873p3.htm
http://xingyunbaijunwei.blog.163.com/blog/static/76538067201241685556302/
http://blog.csdn.net/kkxgx/article/details/7717125
https://banu.com/blog/2/how-to-use-epoll-a-complete-example-in-c/epoll-example.c

10:epool中et和lt的区别与实现原理

select/epoll的区别

select的特点:select 选择句柄的时候,是遍历所有句柄,也就是说句柄有事件响应时,select需要遍历所有句柄才能获取到哪些句柄有事件通知,因此效率是非常低。但是如果连接很少的情况下, select和epoll的LT触发模式相比, 性能上差别不大。

这里要多说一句,select支持的句柄数是有限制的, 同时只支持1024个,这个是句柄集合限制的,如果超过这个限制,很可能导致溢出,而且非常不容易发现问题, TAF就出现过这个问题, 调试了n天,才发现:)当然可以通过修改linux的socket内核调整这个参数。
epoll的特点:epoll对于句柄事件的选择不是遍历的,是事件响应的,就是句柄上事件来就马上选择出来,不需要遍历整个句柄链表,因此效率非常高,内核将句柄用红黑树保存的。

对于epoll而言还有ET和LT的区别,LT表示水平触发,ET表示边缘触发,两者在性能以及代码实现上差别也是非常大的。
epoll的LT和ET的区别

LT:水平触发,效率会低于ET触发,尤其在大并发,大流量的情况下。但是LT对代码编写要求比较低,不容易出现问题。LT模式服务编写上的表现是:只要有数据没有被获取,内核就不断通知你,因此不用担心事件丢失的情况。
ET:边缘触发,效率非常高,在并发,大流量的情况下,会比LT少很多epoll的系统调用,因此效率高。但是对编程要求高,需要细致的处理每个请求,否则容易发生丢失事件的情况。

下面举一个列子来说明LT和ET的区别(都是非阻塞模式,阻塞就不说了,效率太低):

采用LT模式下, 如果accept调用有返回就可以马上建立当前这个连接了,再epoll_wait等待下次通知,和select一样。

但是对于ET而言,如果accpet调用有返回,除了建立当前这个连接外,不能马上就epoll_wait还需要继续循环accpet,直到返回-1,且errno==EAGAIN,TAF里面的示例代码:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: