前言
本博客为个人复习时总结用,无商业目的,其大多数内容皆为博主整理所得,并非原创。侵删。
7层结构
7 应用层 (6 表示层 5 会话层) 4 传输层 3 网络层 2 数据链路层 1 物理层 ;
IP
- A类:0.0.0.0~127.255.255.255
- B类:128.0.0.0~191.255.255.255
- C类:192.0.0.0~223.255.255.255
- D类:224.0.0.0~239.255.255.255
- E类:240.0.0.0~247.255.255.255
A类地址的网络号占1个字节,只有7位可以使用。
可以指派的A类网络号为126(2^7 - 2 ) 个。A类IP地址中网络字段全0表示的是“本网络(A类网络)”的意思
,不用于分配给具体的主机。IP地址中网络号全1表示的是本地环回地址,用于测试本主机的进程之间的通信,
即网络号为127的IP地址。A类地址的主机号占3个字节,所以一个A类网络中可以连接的最大主机数为:2^24-2。主机号全0表示该主机连接的单个网络地址(某个A类网络),主机号全1表示该网络中的所有主机。
B类地址的网络号占2个字节,只有14位可以使用。可以指派的B类网络号为2^14-1(128.0.0.0)不用,最小的网络号为:128.1.0.0。
每一个B类网路可以连接的最大主机数为:2^16-2=65534。(扣除主机号全0和全1的IP地址)。
C类地址的网络号占3个字节,只有21位可以使用。可以指派的C类网络号为221(192.0.0.0不用),最小的网络号为:192.0.1.0。每一个C类主机可以连接的最大主机数为:28-2=254(扣除主机号为全0和全1的IP地址)。
TCP/UDP区别与联系
TCP面向连接,UDP面向非连接即发送数据前不需要建立链接
- TCP提供可靠的服务(数据传输),UDP无法保证
TCP面向字节流,UDP面向报文
- TCP数据传输慢,UDP数据传输快
TCP:
头部(20字节):序号,确认号,接收窗口
三次握手:三次握手的目的是同步连接双方的序列号和确认号并交换 TCP 窗口大小信息。
SYN = 1 时为握手阶段
SYN = 0 时为传输数据阶段
- 停等协议(加入计时器,一次只发送一个包)、流水线协议;
- 流水线协议:GBN和选择重传(加缓冲,知道窗口全部正确接收,再进行下移);
- TCP拥塞控制:
慢启动:
快恢复:与快重传配合:
快重传要求接收方在收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方)而不要等到自己发送数据时捎带确认。快重传算法规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待设置的重传计时器时间到期。
UDP:(无连接)
UDP是面向报文的 头部八个字节
Java编程
-
TCP:
//服务端: ServerSocket serverSocket = new ServerSocket(port); Socket server = serverSocket.accept(); DataInputStream in = new DataInputStream(server.getInputStream()); DataOutputStream out = new DataOutputStream(server.getOutputStream()); 客户端: Socket client = new Socket(serverName, port); OutputStream outToServer = client.getOutputStream(); InputStream inFromServer = client.getInputStream();
-
UDP:
服务端: DatagramSocket socket = new DatagramSocket(12345); DatagramPacket packet = new DatagramPacket(data, data.length); socket.receive(packet);// 此方法在接收到数据报之前会一直阻塞 客户端: DatagramSocket socket = new DatagramSocket(); socket.send(packet);
BIO/NIO/AIO
BIO
在JDK1.4出来之前,我们建立网络连接的时候采用BIO模式,需要先在服务端启动一个ServerSocket,然后在客户端启动Socket来对服务端进行通信
,默认情况下服务端需要对每个请求建立一堆线程等待请求,而客户端发送请求后,先咨询服务端是否有线程相应,如果没有则会一直等待或者遭到拒绝请求,如果有的话,客户端会线程会等待请求结束后才继续执行。
NIO
NIO本身是基于事件驱动思想来完成的,其主要想解决的是BIO的大并发问题: 在使用同步I/O的网络应用中,如果要同时处理多个客户端请求,或是在客户端要同时和多个服务器进行通讯,就必须使用多线程来处理。也就是说,将每一个客户端请求分配给一个线程来单独处理。这样做虽然可以达到我们的要求,但同时又会带来另外一个问题。由于每创建一个线程,就要为这个线程分配一定的内存空间(也叫工作存储器),而且操作系统本身也对线程的总数有一定的限制。如果客户端的请求过多,服务端程序可能会因为不堪重负而拒绝客户端的请求,甚至服务器可能会因此而瘫痪。
NIO基于Reactor,当socket有流可读或可写入socket时,操作系统会相应的通知引用程序进行处理,应用再将流读取到缓冲区或写入操作系统。 也就是说,这个时候,已经不是一个连接就要对应一个处理线程了,而是有效的请求,对应一个线程,当连接没有数据时,是没有工作线程来处理的。
BIO与NIO一个比较重要的不同,是我们使用BIO的时候往往会引入多线程,每个连接一个单独的线程;而NIO则是使用单线程或者只使用少量的多线程,每个连接共用一个线程。
NIO的最重要的地方是当一个连接创建后,不需要对应一个线程,这个连接会被注册到多路复用器上面,所以所有的连接只需要一个线程就可以搞定,当这个线程中的多路复用器进行轮询的时候,发现连接上有请求的话,才开启一个线程进行处理,也就是一个请求一个线程模式。
在NIO的处理方式中,当一个请求来的话,开启线程进行处理,可能会等待后端应用的资源(JDBC连接等),其实这个线程就被阻塞了,当并发上来的话,还是会有BIO一样的问题。
HTTP/1.1出现后,有了Http长连接,这样除了超时和指明特定关闭的http header外,这个链接是一直打开的状态的,这样在NIO处理中可以进一步的进化,在后端资源中可以实现资源池或者队列,当请求来的话,开启的线程把请求和请求数据传送给后端资源池或者队列里面就返回,并且在全局的地方保持住这个现场(哪个连接的哪个请求等),这样前面的线程还是可以去接受其他的请求,而后端的应用的处理只需要执行队列里面的就可以了,这样请求处理和后端应用是异步的.当后端处理完,到全局地方得到现场,产生响应,这个就实现了异步处理。
AIO
与NIO不同,当进行读写操作时,只须直接调用API的read或write方法即可。这两种方法均为异步的,对于读操作而言,当有流可读取时,操作系统会将可读的流传入read方法的缓冲区,并通知应用程序;对于写操作而言,当操作系统将write方法传递的流写入完毕时,操作系统主动通知应用程序。
即可以理解为,read/write方法都是异步的,完成后会主动调用回调函数。
- BIO是一个连接一个线程。
- NIO是一个请求一个线程。
- AIO是一个有效请求一个线程。
Java对BIO、NIO、AIO的支持:
- Java BIO : 同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
- Java NIO : 同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。
- Java AIO(NIO.2) : 异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理,
BIO、NIO、AIO适用场景分析:
-BIO方式适用于连接数目比较小且固定的架构
,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。
NIO方式适用于连接数目多且连接比较短(轻操作)的架构
,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。AIO方式使用于连接数目多且连接比较长(重操作)的架构
,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。
另外,I/O属于底层操作,需要操作系统支持,并发也需要操作系统的支持,所以性能方面不同操作系统差异会比较明显。
在高性能的I/O设计中,有两个比较著名的模式Reactor和Proactor模式,
其中Reactor模式用于同步I/O,而Proactor运用于异步I/O操作。
同步和异步是针对应用程序和内核的交互而言的,同步指的是用户进程触发IO操作并等待或者轮询的去查看IO操作是否就绪,而异步是指用户进程触发IO操作以后便开始做自己的事情,而当IO操作已经完成的时候会得到IO完成的通知。
而阻塞和非阻塞是针对于进程在访问数据的时候,根据IO操作的就绪状态来采取的不同方式,说白了是一种读取或者写入操作函数的实现方式,阻塞方式下读取或者写入函数将一直等待,而非阻塞方式下,读取或者写入函数会立即返回一个状态值。
同步阻塞,同步非阻塞,异步阻塞,异步非阻塞IO
一般来说I/O模型可以分为:同步阻塞,同步非阻塞,异步阻塞,异步非阻塞IO
同步阻塞IO:在此种方式下,用户进程在发起一个IO操作以后,必须等待IO操作的完成,只有当真正完成了IO操作以后,用户进程才能运行。JAVA传统的IO模型属于此种方式!
同步非阻塞IO:在此种方式下,用户进程发起一个IO操作以后边可返回做其它事情,但是用户进程需要时不时的询问IO操作是否就绪,这就要求用户进程不停的去询问,从而引入不必要的CPU资源浪费。其中目前JAVA的NIO就属于同步非阻塞IO。
异步阻塞IO:此种方式下是指应用发起一个IO操作以后,不等待内核IO操作的完成,等内核完成IO操作以后会通知应用程序,因为此时是通过select系统调用来完成的,而select函数本身的实现方式是阻塞的,而采用select函数有个好处就是它可以同时监听多个文件句柄,从而提高系统的并发性!
异步非阻塞IO:在此种模式下,用户进程只需要发起一个IO操作然后立即返回,等IO操作真正的完成以后,应用程序会得到IO操作完成的通知,此时用户进程只需要对数据进行处理就好了,不需要进行实际的IO读写操作,因为真正的IO读取或者写入操作已经由内核完成了。
目前Java中还没有支持此种IO模型。
浏览器输入了www.baidu.com之后有哪些过程
- 先查找对应IP地址:浏览器内部的dns缓存->os中的缓存->host文件
- 若没有,则递归的询问DNS服务器:根服务器->com域服务器->baidu.com服务器->www.baidu.com的IP
- 若还是没有,则访问失败,若找到了,则放入os缓存->浏览器内部缓存
- 根据ip地址,向百度服务器建立连接(三次握手)
- 连接成功了之后发送http请求,获取相应的文件,渲染页面、加载对应的js脚本等
- 断开连接
Web缓存:
一般设置为代理服务器中,进行一些对象的检测。
- 由域名→IP 地址
寻找 IP 地址的过程依次经过了浏览器缓存、系统缓存、hosts文件、路由器缓存、 递归搜索根域名服务器。
- 建立 TCP/IP 连接(三次握手具体过程)
- 由浏览器发送一个 HTTP 请求
- 经过路由器的转发,通过服务器的防火墙,该 HTTP 请求到达了服务器
- 服务器处理该 HTTP 请求,返回一个 HTML 文件
- 浏览器解析该 HTML 文件,并且显示在浏览器端
- 这里需要注意:
HTTP 协议是一种基于 TCP/IP 的应用层协议,进行 HTTP 数据请求必须先建立 TCP/IP 连接
可以这样理解:HTTP 是轿车,提供了封装或者显示数据的具体形式;Socket 是发动机,提供了网络通信的能力。
两个计算机之间的交流无非是两个端口之间的数据通信 , 具体的数据会以什么样的形式展现是以不同的应用层协议来定义的。
DNS解析过程
- 本机向local dns请求 www.baidu.com
- local dns 向根域请求 www.baidu.com,根域返回com.域的服务器IP
- 向 com.域请求 www.baidu.com,com. 域返回 baidu.com 域的服务器IP
- 向 baidu.com 请求 www.baidu.com,返回 cname www.a.shifen.com 和 a.shifen.com 域的服务器IP
- 向 root 域请求 www.a.shifen.com
- 向 com. 域请求 www.a.shife.com
- 向shifen.com请求
- 向a.shifen.com域请求
- 拿到www.a.shifen.com的IP
- localdns 返回本机 www.baidu.com cname www.a.shifen.com 以及 www.a.shifen.com的IP
端口服务
ARP
- 首先,每个主机都会在自己的ARP缓冲区中
建立一个ARP列表,以表示IP地址和MAC地址之间的对应关系。
- 当源主机要发送数据时,首先检查ARP列表中是否有对应IP地址的目的主机的MAC地址,如果有,则直接发送数据,
如果没有,就向本网段的所有主机发送ARP数据包,该数据包包括的内容有:源主机 IP地址,源主机MAC地址,目的主机的IP 地址。
- 当本网络的所有主机收到该ARP数据包时,首先检查数据包中的IP地址是否是自己的IP地址,如果不是,则忽略该数据包,如果是,则首先从数据包中取出源主机的IP和MAC地址写入到ARP列表中,如果已经存在,则覆盖,然后将自己的MAC地址写入ARP响应包中,告诉源主机自己是它想要找的MAC地址。
4.源主机收到ARP响应包后。将目的主机的IP和MAC地址写入ARP列表,并利用此信息发送数据。
如果源主机一直没有收到ARP响应数据包,表示ARP查询失败。
广播发送ARP请求,单播发送ARP响应。
HTTP
无状态
:协议对客户端没有状态存储,对事物处理没有“记忆”能力,比如访问一个网站需要反复进行登录操作无连接
:HTTP/1.1之前,由于无状态特点,每次请求需要通过TCP三次握手四次挥手,和服务器重新建立连接。比如某个客户机在短时间多次请求同一个资源,服务器并不能区别是否已经响应过用户的请求,所以每次需要重新响应请求,需要耗费不必要的时间和流量。- 基于请求和响应:基本的特性,由客户端发起请求,服务端响应
- 简单快速、灵活
- 通信使用明文、请求和响应不会对通信方进行确认、无法保护数据的完整性
HTTP/1.1
解决了1.0版本的keepalive问题,1.1版本加入了持久连接,一个TCP连接可以允许多个HTTP请求;
加入了管道机制,一个TCP连接同时允许多个请求同时发送,增加了并发性;新增了请求方式PUT、PATCH、DELETE等。
但是还存在一些问题,服务端是按队列顺序处理请求的,假如一个请求处理时间很长,则会导致后边的请求无法处理,这样就造成了队头阻塞的问题;同时HTTP是无状态的连接,因此每次请求都需要添加重复的字段,降低了带宽的利用率。
http和websocket的长连接区别
HTTP1.1通过使用Connection:keep-alive进行长连接,HTTP 1.1默认进行持久连接。在一次 TCP 连接中可以完成多个 HTTP 请求,但是对每个请求仍然要单独发 header,Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。这种长连接是一种“伪链接”.
websocket的长连接,是一个真的全双工。长连接第一次tcp链路建立之后,后续数据可以双方都进行发送,不需要发送请求头。
keep-alive双方并没有建立正真的连接会话,服务端可以在任何一次请求完成后关闭。WebSocket 它本身就规定了是正真的、双工的长连接,两边都必须要维持住连接的状态。
HTTP/2.0
为了解决1.1版本利用率不高的问题,提出了HTTP/2.0版本。增加双工模式,即不仅客户端能够同时发送多个请求,服务端也能同时处理多个请求,解决了队头堵塞的问题;
HTTP请求和响应中,状态行和请求/响应头都是些信息字段,并没有真正的数据,因此在2.0版本中将所有的信息字段建立一张表,为表中的每个字段建立索引,客户端和服务端共同使用这个表,他们之间就以索引号来表示信息字段,这样就避免了1.0旧版本的重复繁琐的字段,并以压缩的方式传输,提高利用率。
另外也增加服务器推送的功能,即不经请求服务端主动向客户端发送数据。
根据HTTP标准,HTTP请求可以使用多种请求方法。
GET 请求指定的页面信息,并返回实体主体。
HEAD 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头
POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。
PUT 从客户端向服务器传送的数据取代指定的文档的内容。
DELETE 请求服务器删除指定的页面。
CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
- OPTIONS 允许客户端查看服务器的性能。
- TRACE 回显服务器收到的请求,主要用于测试或诊断。
HTTPS:
基于HTTP协议,通过SSL或TLS提供加密处理数据、验证对方身份以及数据完整性保护
通过抓包可以看到数据不是明文传输,而且HTTPS有如下特点:
- 内容加密:采用混合加密技术,中间者无法直接查看明文内容
- 验证身份:通过证书认证客户端访问的是自己的服务器
- 保护数据完整性:防止传输的内容被中间人冒充或者篡改