网络
5层协议
自下而上分别为物理层,数据链路层,网络层,传输层,应用层。
物理层和数据链路层传送比特位,负责将数据在网络节点上传输。
网络层对应主机之间的通信。
传输层在主机内部为应用层提供传输方式。
TCP,UDP区别
都属于传输层协议。TCP是面向链接的可靠协议;UDP是无链接的不可靠协议。
使用TCP会在通信前先建立链接,之后进行字节流的可靠传输。
但UDP则不会建立链接,直接发送数据。
TCP 可靠机制
可靠分为数据层面和传输层面。数据层面提供了检验和机制。
传输层面则主要提供了保序,不丢失:
- 序列号-每个数据包都有序列号,接收端可以确保数据的顺序可靠。
- 确认机制:发出去的包,需要接收端回复。
- 重传机制:超时重传(发出去的数据包在一定时间内没收到)和快速重传(比如收到了1,3,4包)则会连续发3个1包的确认包告诉发送端快速重传2号包。
除此之外还有传输优化机制,避免网络状况更糟糕: - 拥塞控制
- 滑动窗口
TCP 3次握手,4次挥手
根据上面提到的可靠机制,在建立链接时会分享自己的序列号,同时也需要回复最后一个数据包。
所以3次握手是上述机制的最少通信次数。
A和B建立链接。具体是
- A说:“我的序列号是a,我们建立链接吧(SYN)”。发出去之后A会进入等待状态(TODO)
- B收到后,回复说“我收到了(ACK),我的序列号是b,可以建立链接(SYN)”。之后进入SYN_RCV
- A 收到回复后,知道了序列号号,需要对B的消息进行确认,回复说好的。A进入established,B收到后也进入established。
这期间由于其他机制的需要,也会附带其他信息,比如窗口大小。
至于4次挥手,是因为TCP是双向独立通信的,两个方向的传输需要单独关闭。每一次关闭都需要告知,并且回复确认。总共需要4次。
网络IO 多路复用
作者:Java程序鱼
链接:https://www.zhihu.com/question/28594409/answer/3603682873
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
但是由于读写操作等待用户输入 或 输出都是阻塞的,所以 I/O 操作在一般情况下往往不能直接返回,这会导致某一文件的 I/O 阻塞导,致整个进程无法对其它客户提供服务。而 I/O 多路复用就是为了解决这个问题而出现的。为了让单线程(进程)的服务端应用同时处理多个客户端的事件,Redis 采用了 IO 多路复用机制。
这里“多路”指的是多个网络连接客户端,“复用”指的是复用同一个线程(单进程)。I/O 多路复用其实是使用一个线程来检查多个 Socket 的就绪状态,在单个线程中通过记录跟踪每一个 socket(I/O流)的状态来管理处理多个 I/O 流。如下图是 Redis 的 I/O 多路复用模型:

如上图对 Redis 的 I/O 多路复用模型进行一下描述说明:
- 一个 socket 客户端与服务端连接时,会生成对应一个套接字描述符(套接字描述符是文件描述符的一种),每一个 socket 网络连接其实都对应一个文件描述符。
- 多个客户端与服务端连接时,Redis 使用 I/O 多路复用程序 将客户端 socket 对应的 FD 注册到监听列表(一个队列)中。当客服端执行 read、write 等操作命令时,I/O 多路复用程序会将命令封装成一个事件,并绑定到对应的 FD 上。
- 文件事件处理器使用 I/O 多路复用模块同时监控多个文件描述符(fd)的读写情况,当 accept、read、write 和 close 文件事件产生时,文件事件处理器就会回调 FD 绑定的事件处理器进行处理相关命令操作。
例如:以 Redis 的 I/O 多路复用程序 epoll 函数为例。多个客户端连接服务端时,Redis 会将客户端 socket 对应的 fd 注册进 epoll,然后 epoll 同时监听多个文件描述符(FD)是否有数据到来,如果有数据来了就通知事件处理器赶紧处理,这样就不会存在服务端一直等待某个客户端给数据的情形。
整个文件事件处理器是在单线程上运行的,但是通过 I/O 多路复用模块的引入,实现了同时对多个 FD 读写的监控,当其中一个 client 端达到写或读的状态,文件事件处理器就马上执行,从而就不会出现 I/O 堵塞的问题,提高了网络通信的性能。
操作系统
进程,线程区别和联系
进程是操作系统资源分配的单位,是一个容器。这里资源指内存和IO。
线程是进程里具体执行单位,线程共享进程资源。
进程通信机制
管道,文件,socket,共享内存等
虚拟内存
他是虚拟的,是操作系统逻辑上扩容内存的一种手段。将内存和磁盘进行了统一。为程序访问提供了便利。
线程同步
希望线程以期望的顺序执行,不能乱执行(说明有公共的资源或逻辑)。针对公用块有三种形式:
- 互斥锁。只有拿到锁线程才能访问资源。同时只能有一个线程访问。
- 信号量。跟上面类似,但可以限制同时访问线程的数量。
- 事件(wait/notify)。等待唤醒
死锁
两个或多个进程/线程持有对方资源,并在等待对方所持资源释放,导致陷入互相等待的状态。
死锁形成的4个必要条件:
- 互斥:资源互斥访问的。
- 占有并请求。
- 不可剥夺。
- 循环等待,不放弃。
设计模式
模式分类
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
设计原则
1)开闭原则
开闭原则的意思是:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
2)里氏代换原则
里氏代换原则是面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
3)依赖倒转原则
这个原则是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。
4)接口隔离原则
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。它还有另外一个意思是:降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。
5)迪米特法,又称最少知道原则(Demeter Principl
最少知道原则是指:一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。
6)合成复用原则
合成复用原则是指:尽量使用合成/聚合的方式,而不是使用继承。