基础知识

操作系统

1、进程有哪几种状态,状态转移图,及导致转换的事件

进程有四种特征:1. 动态性 2. 并发性 3. 独立性 4. 异步性

状态:

  1. 就绪态。当进程已经分配到除CPU以外的所有资源,只要获得处理机就可以立即执行。

  2. 执行态。当进程已获得处理机,程序在处理机上执行。

  3. 阻塞态。正在执行的进程,由于等待某个事件发生而无法执行时,便放弃处理机而处于阻塞状态。引起进程阻塞的事件可有多种,例如,等待I/O完成、申请缓冲区不能满足、等待信件(信号)等。

状态转移:

  (1) 就绪→执行
    处于就绪状态的进程,当进程调度程序为之分配了处理机后,该进程便由就绪状态转变成执行状态。

  (2) 执行→就绪
    处于执行状态的进程在其执行过程中,因分配给它的一个时间片已用完而不得不让出处理机,于是进程从执行状态转变成就绪状态。

  (3) 执行→阻塞
    正在执行的进程因等待某种事件发生而无法继续执行时,便从执行状态变成阻塞状态。

  (4) 阻塞→就绪
    处于阻塞状态的进程,若其等待的事件已经发生,于是进程由阻塞状态转变为就绪状态。

2、进程和线程的区别

  1. 进程是资源的分配和调度的一个独立单元,线程是CPU调度的最小单元。

  2. 同一个进程中可以包括多个线程,并且线程共享整个进程的资源(寄存器、堆栈、上下文),一个进行至少包括一个线程。

  3. 线程是轻量级的进程,它的创建和销毁所需要的时间比进程小很多,所有操作系统中的执行功能都是创建线程去完成的。线程用于小任务,而进程用于更多的'重量级'的任务 - 应用基本执行。

      4. 线程中执行时一般都要进行同步和互斥,因为他们共享同一进程的所有资源。
  5. 在同一进程中的线程共享相同的地址空间,而不同的进程没有。因此线程可以读写同样的数据结构和变量,便于线程之间的通信。相反,进程间通信(IPC)很困难且消耗更多资源。

  6. 任务的执行需要依赖各个PC资源,我们可以称为计算机执行的上下文环境。要实现“同时执行”,就需要不断轮换,为了后来继续从当前状态执行下去,计算机需要保存切换前的程序上下文。所以有了进程:用进程去描述程序当前上下文的状态信息----内存位置、变量值、任务ID……所以,进程是资源分配的单位。一般来说宏观上可以看做是一个软件的运行,例如一个word文档的打开。

  7. 多个任务之间切换因为要保存上下文、调入上下文,一旦多了的时候,还是有一定的时间消耗的。为了进一步提高资源利用率,人们在进程中,引入了线程,线程只是CPU轮流调度的单位,其他上下文信息用所在进程中的。这样上下文切换的耗时就降了下来。同样的,宏观上来可以看做是一个软件中的多个处理功能,例如上述打开word中拼写检查功能、字体加粗……

3、进程通信的几种方式

进程通信(IPC:Inter-Process Communication)的目的:数据传输、共享数据、通知事件、资源共享、进程控制。

几种方式:

  1. 管道:速度慢,容量有限,只有父子进程之间能够进行通信,用匿名管道进行通信的进程都有一个共同的祖先进程启动,无法在不相关的进程间通信。命名管道(也被称为FIFO文件,就是一种特殊类型的文件)克服了管道没有名字的限制,除了具有管道的功能外,还允许无亲缘关系进程间的通信。Linux进程间通信——使用命名管道(https://blog.csdn.net/ljianhui/article/details/10202699

  2. 消息队列:由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。https://blog.csdn.net/ljianhui/article/details/10287879

  3. 信号:用于通知接收进程某个事件已经发生。不能传递复杂信息,主要作为进程间以及同一进程不同线程之间的同步手段。

  4. 共享内存:就是映射一段能被其他进程所访问的内存,这段内存由一个进程创建,但多个进程都可以访问。共享内存是最快的IPC方式,它是针对其他进程间通信方式运行效率低而设计的,往往与其他通信机制,如信号量,配合使用,实现进程间的同步和通信(比如一个进程在写的时候,另一个进程要注意读写的问题,相当于线程中的线程安全)。https://blog.csdn.net/ljianhui/article/details/10253345

  5. Socket:套接字也是一种进程通信机制,可用于不同机器间的进程通信。

4、线程同步的方式

线程同步和互斥的定义:

  线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。

  线程互斥是指对于共享的进程系统资源,在各单个线程访问时的排他性。当有若干个线程都要使用某一共享资源时,任何时刻最多只允许一个线程去使用,其他要使用该资源的线程必须等待,直到占用资源者释放该资源。线程互斥可以看成一种特殊的线程同步。

用户线程和内核线程

线程间的同步方法大体可分为两类:

  用户模式和内核模式。内核模式就是指利用系统内核对象的单一性来进行同步,使用时需要切换内核态与用户态。而用户模式就是不需要切换到内核态,只在用户态完成操作。

  用户模式下的方法有:原子操作(例如一个单一的全局变量),临界区(是一段独占对某些共享资源访问的代码,在任意时刻只允许一个线程对共享资源进行访问。如果有多个线程试图同时访问临界区,那么在有一个线程进入后其他所有试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开。临界区在被释放后,其他线程可以继续抢占,并以此达到用原子方式操作共享资源的目的)。

  内核模式下的方法有:事件、信号量、互斥量。

内核模式的方式:

  1. 互斥锁或互斥量使用流程

    在生产者-消费者模式中,我们可以把缓冲区设置为一个互斥量,一次要么生产者要么消费者霸占它。

    - 初始化锁。在使用前,要对它进行初始化。

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

    - 解锁。在完成了对共享资源的访问后,要对互斥量进行解锁。

    - 销毁锁。锁是在使用完成后,需要进行销毁以释放资源。

  2. 读写锁

    读写锁也叫做共享-独占锁,当读写锁以读模式锁住时,它是以共享模式锁住的;当它以写模式锁住时,它是以独占模式锁住的。在生产者-消费者模式中,如果有多个消费者,这个时候就可以把生产者设置为一个写锁,为每个消费者设置一个读锁。

    加锁:当读写锁是写加锁状态时,在这个锁被解锁之前,所有试图对这个锁加锁的线程都会被阻塞。当读写锁在读加锁状态时,所有试图以读模式对它进行加锁的线程都可以得到访问权,但是如果线程希望以写模式对此锁进行加锁,它必须阻塞直到所有的线程释放读锁。

线程同步-生产者消费者问题

 5、内存池、线程池、进程池

  内存池:平常我们使用new、malloc在堆区申请一块内存,但由于每次申请的内存大小不一样就会产生很多碎片,造成不好管理和浪费的情况。内存池是在真正使用内存之前,先申请一定数量的、大小相等(一般情况下)的内存块留作备用。当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够再继续申请新的内存。这样做的一个优点是尽量避免了内存碎片,使得内存分配效率得以提升。

  线程池、进程池:这两个问题有一定的相似度,在面向对象程序编程中,对象的创建与析构都是一个较为复杂的过程,较费时间,所以为了提高程序的运行效率尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁。所以我们可以创建一个进程池(线程池),预先放一些进程(线程)进去,要用的时候就直接调用,用完之后再把进程归还给进程池,省下创建删除进程的时间,不过当然就需要额外的开销了。利用线程池与进程池可以使管理进程与线程的工作交给系统管理,不需要程序员对里面的线程、进程进行管理。

  线程池主要用于:1、需要大量的线程来完成任务,且完成任务的时间比较短。 WEB服务器完成网页请求这样的任务,使用线程池技术是非常合适的。因为单个任务小,而任务数量巨大,你可以想象一个热门网站的点击次数。但对于长时间的任务,比如一个Telnet连接请求,线程池的优点就不明显了。因为Telnet会话时间比线程的创建时间大多了。

  2、对性能要求苛刻的应用,比如要求服务器迅速响应客户请求。

  3、接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用。突发性大量客户请求,在没有线程池情况下,将产生大量线程,虽然理论上大部分操作系统线程数目最大值不是问题,短时间内产生大量线程可能使内存到达极限,并出现"OutOfMemory"的错误。

6、死锁的概念,导致死锁的原因

  可以把死锁定义为一组相互竞争系统资源或进行通信的进程间的“永久”阻塞。当一组进程中的每个进程都在等待某个事件(典型的情况是等待所请求的资源释放),而只有在这组进程中的其他被阻塞的进程才可以触发该事件,这时就称这组进程发生死锁。因为没有事件能够被触发,所以死锁是永久性的。

  导致死锁的原因:1. 互斥,一次只有一个线程能够使用一个资源。其他线程不能访问已分配给其他线程的资源。

    2. 占有且等待,当一个线程等待其他线程时,继续占有已经分配的资源。

    3. 不可抢占,不能抢占线程已占有的资源。

    4. 循环等待,存在一个封闭的线程链,使得每个进程至少占有此链中下一个进程所需要的一个资源。

7、预防死锁的方式

  死锁的预防是保证系统不进入死锁状态的一种策略。它的基本思想是要求进程申请资源时遵循某种协议,从而打破产生死锁的四个必要条件中的一个或几个,保证系统不会进入死锁状态。

  (1)破坏互斥条件。即允许进程同时访问某些资源。但是,有的资源是不允许被同时访问的,像打印机等等,这是由资源本身的属性所决定的。所以,这种办法并无实用价值。

  (2)破坏不可剥夺条件。即允许进程强行从占有者那里夺取某些资源。就是说,当一个进程已占有了某些资源,它又申请新的资源,但不能立即被满足时,它必须释放所占有的全部资源,以后再重新申请。它所释放的资源可以分配给其它进程。这就相当于该进程占有的资源被隐蔽地强占了。这种预防死锁的方法实现起来困难,会降低系统性能。    

  (3)破坏请求与保持条件。可以实行资源预先分配策略。即进程在运行前一次性地向系统申请它所需要的全部资源。如果某个进程所需的全部资源得不到满足,则不分配任何资源,此进程暂不运行。只有当系统能够满足当前进程的全部资源需求时,才一次性地将所申请的资源全部分配给该进程。由于运行的进程已占有了它所需的全部资源,所以不会发生占有资源又申请资源的现象,因此不会发生死锁。但是,这种策略也有如下缺点:

    1. 在许多情况下,一个进程在执行之前不可能知道它所需要的全部资源。这是由于进程在执行时是动态的,不可预测的;

    2. 资源利用率低。无论所分资源何时用到,一个进程只有在占有所需的全部资源后才能执行。即使有些资源最后才被该进程用到一次,但该进程在生存期间却一直占有它们,造成长期占着不用的状况。这显然是一种极大的资源浪费;

    3. 降低了进程的并发性。因为资源有限,又加上存在浪费,能分配到所需全部资源的进程个数就必然少了。    

  (4)破坏循环等待条件,实行资源有序分配策略。采用这种策略,即把资源事先分类编号,按号分配,使进程在申请,占用资源时不会形成环路。所有进程对资源的请求必须严格按资源序号递增的顺序提出。进程占用了小号资源,才能申请大号资源,就不会产生环路,从而预防了死锁。这种策略与前面的策略相比,资源的利用率和系统吞吐量都有很大提高,但是也存在以下缺点:

    1. 限制了进程对资源的请求,同时给系统中所有资源合理编号也是件困难事,并增加了系统开销;

    2. 为了遵循按编号申请的次序,暂不使用的资源也需要提前申请,从而增加了进程对资源的占用时间。

8、死锁的检测与恢复

  一般来说,由于操作系统有并发,共享以及随机性等特点,通过预防和避免的手段达到排除死锁的目的是很困难的。这需要较大的系统开销,而且不能充分利用资源。为此,一种简便的方法是系统为进程分配资源时,不采取任何限制性措施,但是提供了检测和解脱死锁的手段:能发现死锁并从死锁状态中恢复出来。因此,在实际的操作系统中往往采用死锁的检测与恢复方法来排除死锁。常利用资源分配图、进程等待图来协助这种检测。

  死锁检测与恢复是指系统设有专门的机构,当死锁发生时,该机构能够检测到死锁发生的位置和原因,并能通过外力破坏死锁发生的必要条件,从而使得并发进程从死锁状态中恢复出来。一旦在死锁检测时发现了死锁,就要消除死锁,使系统从死锁状态中恢复过来。  

    (1)最简单,最常用的方法就是进行系统的重新启动,不过这种方法代价很大,它意味着在这之前所有的进程已经完成的计算工作都将付之东流,包括参与死锁的那些进程,以及未参与死锁的进程。

    (2)撤消进程,剥夺资源。终止参与死锁的进程,收回它们占有的资源,从而解除死锁。这时又分两种情况:一次性撤消参与死锁的全部进程,剥夺全部资源;或者逐步撤消参与死锁的进程,逐步收回死锁进程占有的资源。一般来说,选择逐步撤消的进程时要按照一定的原则进行,目的是撤消那些代价最小的进程,比如按进程的优先级确定进程的代价;考虑进程运行时的代价和与此进程相关的外部作业的代价等因素。 

  此外,还有进程回退策略,即让参与死锁的进程回退到没有发生死锁前某一点处,并由此点处继续执行,以求再次执行时不再发生死锁。虽然这是个较理想的办法,但是操作起来系统开销极大,要有堆栈这样的机构记录进程的每一步变化,以便今后的回退,有时这是无法做到的。

参考

9、用户态和内核态

内核态与用户态的区别:

1)内核态与用户态是操作系统的两种运行级别,当程序运行在3级特权级上时,就可以称之为运行在用户态。因为这是最低特权级,是普通的用户进程运行的特权级,大部分用户直接面对的程序都是运行在用户态;
2)当程序运行在0级特权级上时,就可以称之为运行在内核态。
3)运行在用户态下的程序不能直接访问操作系统内核数据结构和程序。当我们在系统中执行一个程序时,大部分时间是运行在用户态下的,在其需要操作系统帮助完成某些它没有权力和能力完成的工作时就会切换到内核态。    
4)这两种状态的主要差别是:
处于用户态执行时,进程所能访问的内存空间和对象受到限制,其所处于占有的处理机是可被抢占的 ;
而处于核心态执行中的进程,则能访问所有的内存空间和对象,且所占有的处理机是不允许被抢占的。
 
以下三种情况会导致用户态到内核态的切换:
1)系统调用
这是用户态进程主动要求切换到内核态的一种方式,用户态进程通过系统调用申请使用操作系统提供的服务程序完成工作。比如前例中fork()实际上就是执行了一个创建新进程的系统调用。
而系统调用的机制其核心还是使用了操作系统为用户特别开放的一个中断来实现,例如Linux的int 80h中断。
2)异常
当CPU在执行运行在用户态下的程序时,发生了某些事先不可知的异常,这时会触发由当前运行进程切换到处理此异常的内核相关程序中,也就转到了内核态,比如缺页异常。 
3)外围设备的中断 
当外围设备完成用户请求的操作后,会向CPU发出相应的中断信号,这时CPU会暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序,
如果先前执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了由用户态到内核态的切换。比如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后续操作等。
 
这3种方式是系统在运行时由用户态转到内核态的最主要方式,其中系统调用可以认为是用户进程主动发起的,异常和外围设备中断则是被动的。
 
10、用户栈和内核栈

进程的堆栈

每个进程都有自己的堆栈,内核在创建一个新的进程时,在创建进程控制块task_struct的同时,也为进程创建自己堆栈。一个进程 有2个堆栈,用户堆栈和系统堆栈;用户堆栈的空间指向用户地址空间,内核堆栈的空间指向内核地址空间。当进程在用户态运行时,CPU堆栈指针寄存器指向的 用户堆栈地址,使用用户堆栈,当进程运行在内核态时,CPU堆栈指针寄存器指向的是内核栈空间地址,使用的是内核栈;

进程用户栈和内核栈之间的切换

当进程由于中断或系统调用从用户态转换到内核态时,进程所使用的栈也要从用户栈切换到内核栈。系统调用实质就是通过指令产生中断,称为软中断。进程因为中断(软中断或硬件产生中断),使得CPU切换到特权工作模式,此时进程陷入内核态,进程进入内核态后,首先把用户态的堆栈地址保存在内核堆栈中,然后设置堆栈指针寄存器的地址为内核栈地址,这样就完成了用户栈向内核栈的切换。

当进程从内核态切换到用户态时,最后把保存在内核栈中的用户栈地址恢复到CPU栈指针寄存器即可,这样就完成了内核栈向用户栈的切换。

这里要理解一下内核堆栈。前面我们讲到,进程从用户态进入内核态时,需要在内核栈中保存用户栈的地址。那么进入内核态时,从哪里获得内核栈的栈指针呢?

要解决这个问题,先要理解从用户态刚切换到内核态以后,进程的内核栈总是空的。这点很好理解,当进程在用户空间运行时,使用的是用户 栈;当进程在内核态运行时,内核栈中保存进程在内核态运行的相关信息,但是当进程完成了内核态的运行,重新回到用户态时,此时内核栈中保存的信息全部恢 复,也就是说,进程在内核态中的代码执行完成回到用户态时,内核栈是空的。

理解了从用户态刚切换到内核态以后,进程的内核栈总是空的,那刚才这个问题就很好理解了,因为内核栈是空的,那当进程从用户态切换到内核态后,把内核栈的栈顶地址设置给CPU的栈指针寄存器就可以了。

11、磁盘的结构

https://blog.csdn.net/hguisu/article/details/7408047

https://www.zhihu.com/question/20537787

12、B-/+ Tree

https://www.kancloud.cn/kancloud/theory-of-mysql-index/41844 

13、LSM

http://www.open-open.com/lib/view/open1424916275249.html

https://blog.csdn.net/wl044090432/article/details/54409278

14、BloomFilter

http://www.cnblogs.com/chenny7/p/4074250.html

 

计算机网络

1、TIME_WAIT状态的概念和意义

ACK:确认字符,在数据通信中,接收站发给发送站的一种传输控制字符,表示发来的数据已确认接收无误。

FIN:结束标志,带有该标志位置的数据包用来结束一个TCP会话,但对应端口仍保持开放状态,准备接收后续数据。

TIME_WAIT是TCP连接中选择主动断开的一方在发送最后一个ACK后保持的一种状态,目的在于在不可靠的网络环境中保持可靠的TCP连接。其通常的维持时间为2 * MSL(Maximum Segment Lifetime,是一个数据包在网络环境中存活的最大时间。如果经过了该时间,数据包仍然没有被接收,那么将会被丢弃)。这样设置的原因是,如果主动断开的一方发送的ACK产生延迟,会导致对方重新发送FIN,极端情况下,这一来一回的时间大约为2 * MSL。TIME_WAIT的时间可以进行设置,不同的操作系统也可能不一样,由内核决定。

解决方法:虽然一个TIME_WAIT网络连接耗费的资源无非是一个端口和一点内存,但是如果是服务器端对应客户端基数比较大的情况下,也会存在问题。所以在HTTP协议头部有一个Connection,有两个值close和keep-alive,相当于告诉服务器在执行完请求后是关闭连接还是保持连接。默认为关闭,那么TIME_WAIT状态出现在服务器端,会造成服务器压力过大。可以选择keep-alive。也可以使用tcp_tw_reuse来设置当新的请求进来后,复用处于TIME_WAIT的socket。

CLOSE_WAIT状态是被动关闭连接的一方在响应主动关闭的一方发送的FIN包之后,处于的一种状态,这种状态在其本身发送FIN之后转移到LAST_ACK状态时消除。CLOSE_WAIT状态数过多一般由于对方关闭连接后,本方未察觉到,没有及时关闭连接导致的,可能有以下几种情况:

1、程序问题:如果代码层面忘记了 close 相应的 socket 连接,那么自然不会发出 FIN 包,从而导致 CLOSE_WAIT 累积;或者代码不严谨,出现死循环之类的问题,导致即便后面写了 close 也永远执行不到。

2、响应太慢或者超时设置过小:如果连接双方不和谐,一方不耐烦直接 timeout,另一方却还在忙于耗时逻辑,就会导致 close 被延后。响应太慢是首要问题,不过换个角度看,也可能是 timeout 设置过小。

3、BACKLOG 太大:此处的 backlog 不是 syn backlog,而是 accept 的 backlog,如果 backlog 太大的话,设想突然遭遇大访问量的话,即便响应速度不慢,也可能出现来不及消费的情况,导致多余的请求还在队列里就被对方关闭了。

CLOSE_WAIT状态的原因与解决方法

浅谈CLOSE_WAIT

再叙TIME_WAIT 

2、在访问一个网站的过程中,发生了什么

1. 解析域名,找到对应的IP

  (1) 先在浏览器缓存里找。浏览器会缓存DNS一段时间,一般2-30分钟。如果有缓存,直接返回IP,否则,下一步。

  (2) 缓存中无法找到IP,会进行系统调用,查询hosts文件。如果找到,直接返回IP,否则下一步。(在计算机本地目录etc下有一个hosts文件,保存着域名与IP地址的对应)

  (3) 进行了上述查询无果,只能借助于网络。路由器一般会有自己的DNS缓存,ISP服务器DNS缓存,一般这一步都能够得到对应的IP。如果还是无果,只能借助于DNS递归解析了。

  (4) ISP的DNS服务器就会开始从根域名服务器开始递归搜索,从.com顶级域名服务器,到baidu的域名服务器。

2. 浏览器与网站建立TCP连接

  浏览器利用IP直接与服务器通信。浏览器发送TCP(SYN标志位为1)连接请求,主机返回TCP(SYN,ACK标志位均为1)应答报文,浏览器收到应答报文发现ACK标志位为1,表示连接请求确认。浏览器返回TCP()确认报文,主机收到确认报文,三次握手,TCP链接建立完成。

3. 浏览器发出GET请求

  浏览器向主机发起一个HTTP-GET方法报文请求。请求中包含访问的URL,也就是http://www.baidu.com/ ,还有User-Agent用户浏览器操作系统信息,编码等。值得一提的是Accep-Encoding和Cookies项。Accept-Encoding一般采用gzip,压缩之后传输html文件。Cookies如果是首次访问,会提示服务器建立用户缓存信息,如果不是,可以利用Cookies对应键值,找到相应缓存,缓存里面存放着用户名,密码和一些用户设置项。

4. 显示页面或返回其他

  返回状态码200 OK,表示服务器可以相应请求,返回报文,由于在报头中Content-type为“text/html”,浏览器以HTML形式呈现,而不是下载文件。

   但是,对于大型网站存在多个主机站点,往往不会直接返回请求页面,而是重定向。返回的状态码就不是200 OK,而是301,302以3开头的重定向码,浏览器在获取了重定向响应后,在响应报文中Location项找到重定向地址,浏览器重新第一步访问即可。

  补充一点的就是,重定向是为了负载均衡或者导入流量,提高SEO排名。利用一个前端服务器接受请求,然后负载到不同的主机上,可以大大提高站点的业务并发处理能力;重定向也可将多个域名的访问,集中到一个站点;由于baidu.com,www.baidu.com会被搜索引擎认为是两个网站,照成每个的链接数都会减少从而降低排名,永久重定向会将两个地址关联起来,搜索引擎会认为是同一个网站,从而提高排名。

3、IP报文的格式和大小限制,格式中字段的含义

版本:指IP协议的版本。

首部长度:首部的长度

服务类型:如下图:

 

其中优先级用来区别优先级别不同的IP报文。

D表示要求有更低的时延。

T表示要求有更高的吞吐量。

R表示要求有更高的可靠性。

总长度:报文的长度。

标识:由于数据报长度超过传输网络的MTU(最大传输单元)而必须分片,这个标识字段的值被复制到所有数据报分片的标识字段中,使得这些分片在达到最终的目的地时可以依照标识字段的内容重新组成原先的数据报。

标志:最低位是MF,MF=1时,表示后面还有分片。

         中间位的DF,DF=1时,表示不能分片。

片偏移: 和前面的数据分片相关,是本分片在原先数据报文中相对首位的偏移位。

生存时间:数据报在网络中存活的时间,所允许通过的路由器的最大数量,没通过一个路由器,该值自动减一,如果数值为0,路由器就可以把该数据报丢弃。

协议: 指出数据报携带的数据是使用何种协议,以便目的主机的IP层能知道次数据报上交到哪一个进程(不同协议有一个专门不同的进程处理)。

首部校验位和:对首部进行校验运算。

  校验方法 : 在发送端,将IP数据报首部划分为多个16位的二进制序列,并将首部校验和字段置为0,用反码运算将所有16位序列对位相加后,将得到多的和的反码写入首部校验和字段。接收端接收到数据报后,将数据报首部的所有字段组织成多个16位的二进制序列,再使用反码运算相加一次,将得到的结果取反。如果结果为0代表没出错,否则出错。

源地址:发送数据报的节点地址。

目的地址:接受数据报的节点地址。 

4、IP数据包、TCP数据包、UDP数据包的区别与联系

IP数据包包含TCP数据包或UDP数据包,IP是第三层(网络层)的协议,TCP与UDP都属于第四层(传输层)的协议。

TCP——传输控制协议,提供的是面向连接的、可靠的字节流服务。当客户与服务器彼此交换数据前,必须先在双方建立一个TCP连接,之后才能传输数据。TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传向另一端。

UDP——用户数据报协议,是一个简单的面向数据报的运输层协议。UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们到达目的地。由于UDP在传输前不用在客户和服务端之间建立连接,且没有超时重发机制,故而传输速度很快。

关键点区分:

  1. 基于连接与无连接

  2. 对系统资源的要求(TCP多,UDP少)

  3. UDP程序结构较简单

  4. 流模式与数据报模式

  5. TCP保证数据的正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证

应用:

TCP发送的包有序号,对方收到包后要给一个反馈,如果超过一定时间还没收到反馈就自动执行超时重发,因此TCP最大的优点是可靠。一般网页(http)、邮件(SMTP)、远程连接(Telnet)、文件(FTP)传送就用TCP
UDP是面向消息的协议,通信时不需要建立连接,数据的传输自然是不可靠的,一般用于多点通信和实时的数据业务,比如语音广播、视频、QQ、TFTP(简单文件传送)、SNMP(简单网络管理协议)、RTP(实时传送协议)RIP(路由信息协议,如报告股票市场,航空信息)、DNS(域名解释)。注重速度流畅。

5、RPC(Remote Process Call Protocol)

  RPC是指远程过程调用,也就是说两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。

那么:

  首先,要解决通讯的问题,主要是通过在服务器和客户端之间建立TCP连接,远程过程调用的所有交换的数据都在这个连接里传输。连接可以是按需连接,调用结束后就断掉,也可以是长连接,多个远程调用共享同一个连接。

  第二,要解决寻址的问题,也就是说,A服务器上的应用怎么告诉底层的RPC框架,如何连接到B服务器(IP地址或主机)以及特定的端口,方法的名称是什么,这样才能完成调用。比如基于Web服务协议栈的RPC,就要提供一个endpoint URI,或者是从UDDI服务上查找。如果是RMI调用,还需要一个RMI Registry来注册服务的地址。

  第三,当A服务器上的应用发起远程过程调用时,方法的参数需要通过底层的网络协议如TCP传递到B服务器,由于网络协议是基于二进制的,内存中的参数的值要序列化为二进制的形式,也就是序列化(Serialize)或编组(Marshal),通过寻址和传输将序列化的二进制发送给B服务器。

  第四,B服务器收到请求后,需要对参数进行反序列化(序列化的逆操作),恢复为内存中的表达方式,然后找到对应的方法(寻址的一部分)进行本地调用,然后得到返回值。

  第五,返回值还要发送回服务器A上的应用,也要经过序列化的方式发送,服务器A接到后,再反序列化,恢复为内存中的表达方式,交给A服务器上的应用。

RPC

6、Socket 编程

  网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端就叫一个Socket。建立网络通信连接至少要一对端口号(socket)。socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。Socket至少包含的信息有协议族、Socket类型、地址和端口。

  建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket ,另一个运行于服务器端,称为ServerSocket 。

  套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。

  1、服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求。

  2、客户端请求:指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。

  3、连接确认:当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,双方就正式建立连接。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。

 

数据结构

1、小根堆、大根堆

  小根堆和大根堆的表示都是一棵完全二叉树,可以用数组来进行存储和表示,下标为i的结点其左子结点为(2*i + 1),右子结点为(2*i + 2)。用小根堆举例,其满足的条件是根结点的值一定小于其子结点。

  堆的插入:将新的元素构成的结点加入到堆的末尾,然后从这个结点往根结点依次更新树的结点分布,以恢复树的次序。

  堆的删除:每次都删除的是堆的根结点。为了便于重建堆,实际的操作是将最后一个数据的值赋给根结点,然后再从根结点开始进行一次从上向下的调整。调整时先在左右儿子结点中找最大的,如果父结点比这个最小的子结点还大说明不需要调整了,反之将父结点和它交换后再考虑后面的结点。相当于从根结点将一个数据的“下沉”过程。

  堆排序:每次输出根结点,然后对堆进行重排后再依次输出。

2、红黑树

  是HashMap的实现结构,是一棵用红黑对结点标色的二叉查找树,通过满足下列特性:

  1. 节点是红色或黑色。
  2. 根是黑色。
  3. 所有叶子都是黑色(叶子是NIL节点)。
  4. 每个红色节点必须有两个黑色的子节点。(从每个叶子到根的所有路径上不能有两个连续的红色节点。)
  5. 从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。

  确保了红黑树的关键特性:从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。结果是这个树大致上是平衡的。因为操作比如插入、删除和查找某个值的最坏情况时间都要求与树的高度成比例,这个在高度上的理论上限允许红黑树在最坏情况下都是高效的,而不同于普通的二叉查找树

posted @ 2018-03-15 20:43  hopelee  阅读(362)  评论(0编辑  收藏  举报