网络编程
网络编程
网络基础
网络编程概念
概念 | 说明 |
---|---|
网络编程 | 网络编程的本质是多台计算机之间的数据交换。数据传递本身没有多大的难度,不就是把一个设备中的数据发送给其他设备,然后接受另外一个设备反馈的数据。现在的网络编程基本上都是基于请求/响应方式的,也就是一个设备发送请求数据给另外一个,然后接收另一个设备的反馈。在网络编程中,发起连接程序,也就是发送第一次请求的程序,被称作客户端(Client),等待其他程序连接的程序被称作服务器(Server)。客户端程序可以在需要的时候启动,而服务器为了能够时刻相应连接,则需要一直启动。例如以打电话为例,首先拨号的人类似于客户端,接听电话的人必须保持电话畅通类似于服务器。连接一旦建立以后,就客户端和服务器端就可以进行数据传递了,而且两者的身份是等价的。在一些程序中,程序既有客户端功能也有服务器端功能,最常见的软件就是QQ、微信这类软件了。 |
网络通信协议 | 位于同一个网络中的计算机在进行连接和通信时需要遵守一定的规则,这些规则就是网络通信协议,它对数据的传输格式、速率、步骤做了统一规定,通信双方必须同时遵守才能完成数据交换。 |
OSI七层模型
OSI(Open System Interconnect),即开放式系统互联。一般都叫OSI参考模型,是ISO(国际标准化组织)组织在1985年研究的网络互连模型。ISO为了更好的使网络应用更为普及,推出了OSI参考模型,这样所有的公司都按照统一的标准来指定自己的网络,就可以互通互联了。OSI定义了网络互连的七层框架(物理层、数据链路层、网络层、传输层、会话层、表示层、应用层)。
TCP/IP四层模型
1)应用层:应用层最靠近用户的一层,是为计算机用户提供应用接口,也为用户直接提供各种网络服务。我们常见应用层的网络服务协议有:HTTP,HTTPS,FTP,TELNET等。
2)传输层:建立了主机端到端的链接,传输层的作用是为上层协议提供端到端的可靠和透明的数据传输服务,包括处理差错控制和流量控制等问题。该层向高层屏蔽了下层数据通信的细节,使高层用户看到的只是在两个传输实体间的一条主机到主机的、可由用户控制和设定的、可靠的数据通路。我们通常说的,TCP、UDP就是在这一层,端口号既是这里的端。
3)网络层:本层通过IP寻址来建立两个节点之间的连接,为源端的运输层送来的分组,选择合适的路由和交换节点,正确无误地按照地址传送给目的端的运输层,就是通常说的IP层。这一层就是我们经常说的IP协议层,IP协议是Internet的基础。
4)数据链路层:通过一些规程或协议来控制这些数据的传输,以保证被传输数据的正确性。实现这些规程或协议的硬件和软件加到物理线路,这样就构成了数据链路。
套接字
TCP用主机的IP地址加上主机上的端口号作为TCP连接的端点,这种端点就叫做套接字(socket)或插口。套接字用(IP地址:端口号)表示。它是网络通信过程中端点的抽象表示,包含进行网络通信必需的五种信息:连接使用的协议、本地主机的IP地址、本地进程的协议端口、远地主机的IP地址、远地进程的协议端口。
ARP协议
ARP协议完成了IP地址与物理地址的映射。每一个主机都设有一个ARP高速缓存,里面有所在的局域网上的各主机和路由器的IP地址到硬件地址的映射表。当源主机要发送数据包到目的主机时,会先检查自己的ARP高速缓存中有没有目的主机的MAC地址,如果有,就直接将数据包发到这个MAC地址,如果没有,就向所在的局域网发起一个ARP请求的广播包(在发送自己的ARP请求时,同时会带上自己的IP地址到硬件地址的映射),收到请求的主机检查自己的IP地址和目的主机的IP地址是否一致,如果一致,则先保存源主机的映射到自己的ARP缓存,然后给源主机发送一个ARP响应数据包。源主机收到响应数据包之后,先添加目的主机的IP地址与MAC地址的映射,再进行数据传送。如果源主机一直没有收到响应,表示ARP查询失败。如果所要找的主机和源主机不在同一个局域网上,那么就要通过ARP找到一个位于本局域网上的某个路由器的硬件地址,然后把分组发送给这个路由器,让这个路由器把分组转发给下一个网络,剩下的工作就由下一个网络来做。
IP与MAC
IP是英文Internet Protocol的缩写,意思是“网络之间互连的协议”,也就是为计算机网络相互连接进行通信而设计的协议,我们可以把ip地址类比成电话号码。在因特网中,它是能使连接到网上的所有计算机网络实现相互通信的一套规则,规定了计算机在因特网上进行通信时应当遵守的规则。任何厂家生产的计算机系统,只要遵守IP协议就可以与因特网互连互通。IP地址大致可分为ipv4和ipv6两种,通常我们说的IP地址都指的的ipv4地址。IPv4地址由用点分隔开的4个8位二进制数构成,一共32位。位了方便记忆我们通常以十进制的方式书写,如192.168.0.1就是一个IP地址,这种写法叫点分十进制格式。IP地址由网络地址和主机地址两部分组成,分配给这两部分的位数因地址类(A类、B类、C类等)的不同而不同。网络地址用于路由选择,而主机地址用于在网络或子网内部寻找一个单独的主机。MAC(Media Access Control,介质访问控制)地址,也叫硬件地址,长度是48比特(6字节),由16进制的数字组成,分为前24位和后24位:前24位叫做组织唯一标志符(Organizationally Unique Identifier,即OUI),是由IEEE的注册管理机构给不同厂家分配的代码,区分了不同的厂家。后24位是由厂家自己分配的,称为扩展标识符。同一个厂家生产的网卡中MAC地址后24位是不同的。我们可以简单的将mac地址类比为sim卡的硬件串号。IP与MAC区别如下:
1、mac地址工作在osi参考模型的第二层,即数据链路层;ip地址工作在第三层即网络层。
2、表示方法和长度不同。
3、mac地址硬件出厂即固化在硬件里,不可随意更改;ip地址人为指定,符合网络要求的情况下可以随意更改。
注:在一台需要联网的主机网卡上既有mac地址又有ip地址,arp协议负责从ip地址中解析出mac地址。
NAT网络地址转换
NAT (Network Address Translation, 网络地址转换):用于解决内网中的主机要和因特网上的主机通信。由NAT路由器将主机的本地IP地址转换为全球IP地址,分为静态转换(转换得到的全球IP地址固定不变)和动态NAT转换。
对称加密与非对称加密
对称加密:是指加密和解密使用同一个密钥的方式,这种方式存在的最大问题就是密钥发送问题,即如何安全地将密钥发给对方。常用的对称加密方法有:DES、3DES、AES。
非对称加密:是指使用一对非对称密钥,即公钥和私钥,公钥可以随意发布,但私钥只有自己知道。发送密文的一方使用对方的公钥进行加密处理,对方接收到加密信息后,使用自己的私钥进行解密。由于非对称加密的方式不需要发送用来解密的私钥,所以可以保证安全性;但是和对称加密比起来,非常的慢。常见非对称加密方式的有:RSA、DSA。
从输入地址到获得页面的过程
1)浏览器查询DNS,获取域名对应的IP地址。具体过程包括浏览器搜索自身的DNS缓存、搜索操作系统的DNS缓存、读取本地的Host文件和向本地DNS服务器进行查询等。对于向本地DNS服务器进行查询,如果要查询的域名包含在本地配置区域资源中,则返回解析结果给客户机,完成域名解析(此解析具有权威性);如果要查询的域名不由本地DNS服务器区域解析,但该服务器已缓存了此网址映射关系,则调用这个IP地址映射,完成域名解析(此解析不具有权威性)。如果本地域名服务器并未缓存该网址映射关系,那么将根据其设置发起递归查询或者迭代查询。
2)浏览器获得域名对应的IP地址以后,浏览器向服务器请求建立链接,发起三次握手。
3)TCP/IP链接建立起来后,浏览器向服务器发送HTTP请求。
4)服务器接收到这个请求,并根据路径参数映射到特定的请求处理器进行处理,并将处理结果及相应的视图返回给浏览器。
5)浏览器解析并渲染视图,若遇到对js文件、css文件及图片等静态资源的引用,则重复上述步骤并向服务器请求这些资源。
6)浏览器根据其请求到的资源、数据渲染页面,最终向用户呈现一个完整的页面。
扩展知识
软件设计师网络相关知识:https://www.cnblogs.com/xdzy/p/16351604.html
网络IO
IO概念
IO | 说明 |
---|---|
文件IO | Java中IO是以流为基础进行数据的输入输出的,所有数据被串行化(所谓串行化就是数据要按顺序进行输入输出)写入输出流。简单来说就是Java通过IO流方式和外部设备进行交互。在Java类库中,IO部分的内容是很庞大的,因为它涉及的领域很广泛:标准输入输出,文件的操作,网络上的数据传输流,字符串流,对象流等等等。比如程序从服务器上下载图片,就是通过流的方式从网络上以流的方式到程序中,再到硬盘中。 |
BIO(Block IO) | 同步并阻塞,服务器实现一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,没处理完之前此线程不能做其他操作,当然可以通过线程池机制改善。BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。IO操作时会阻塞线程,并发处理能力低。我们熟知的Socket编程就是BIO,一个socket连接一个处理线程(这个线程负责这个Socket连接的一系列数据传输操作)。阻塞的原因在于:操作系统允许的线程数量是有限的,多个socket申请与服务端建立连接时,服务端不能提供相应数量的处理线程,没有分配到处理线程的连接就会阻塞等待或被拒绝。在JDK1.4之前,我们建立网络连接的时候只能采用BIO,需要先在服务端启动一个ServerSocket,然后在客户端启动Socket来对服务端进行通信,默认情况下服务端需要对每个请求建立一个线程等待请求,而客户端发送请求后,先咨询服务端是否有线程响应,如果没有则会一直等待或者遭到拒绝,如果有的话,客户端线程会等待请求结束后才继续执行,这就是阻塞式IO。 |
NIO(None-Block IO) | 同步非阻塞,服务器实现一个连接一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4之后开始支持。NIO是对BIO的改进,基于Reactor模型。我们知道,一个socket连接只有在特定时候才会发生数据传输IO操作,大部分时间这个数据通道是空闲的,但还是占用着线程。NIO作出的改进就是一个请求一个线程,在连接到服务端的众多socket中,只有需要进行IO操作的才能获取服务端的处理线程进行IO。这样就不会因为线程不够用而限制了socket的接入。这是JDK提供的新API,从JDK1.4开始,Java提供了一系列改进的输入/输出的新特性,被统称为NIO。新增了许多用于处理输入输出的类,这些类都被放在java.nio包及子包下,并且对原java.io包中的很多类进行改写,新增了满足NIO的功能。 |
AIO(Asynchronous I/O) | 异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由操作系统先完成了再通知服务器应用去启动线程进行处理,AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用操作系统参与并发操作,编程比较复杂,JDK1.7之后开始支持。AIO属于NIO包中的类实现,其实IO主要分为BIO和NIO,AIO只是附加品,解决IO不能异步的实现。在以前很少有Linux系统支持AIO,Windows的IOCP就是该AIO模型。但是现在的服务器一般都是支持AIO操作。在进行I/O编程中,常用到两种模式:Reactor和Proactor。Java的NIO就是Reactor,当有事件触发时,服务器端得到通知,进行相应的处理。AIO即NIO2.0,叫做异步不阻塞的IO。AIO引入异步通道的概念,采用了Proactor模式,简化了程序编写,一个有效的请求才启动一个线程,它的特点是先由操作系统完成后才通知服务端程序启动线程去处理,一般适用于连接数较多且连接时间较长的应用。 |
Netty | Netty是由JBOSS提供的一个Java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。Netty是一个基于NIO的客户、服务器端编程框架,使用Netty可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用。Netty相当简化和流线化了网络应用的编程开发过程,例如,TCP和UDP的socket服务开发。Netty是由NIO演进而来,使用过NIO编程的用户就知道NIO编程非常繁重,Netty是能够能更好的使用NIO。Netty的原理就是NIO,他是基于NIO的一个完美的封装,并且优化了NIO,使用他非常方便,简单快捷。 |
NIO组成
组成 | 说明 |
---|---|
通道(Channel) | Channel是一个对象,可以通过它读取和写入数据。通常我们都是将数据写入包含一个或者多个字节的缓冲区,然后再将缓存区的数据写入到通道中,将数据从通道读入缓冲区,再从缓冲区获取数据。Channel 类似于原IO中的流(Stream),但有所区别,流是单向的,通道是双向的,可读可写。流读写是阻塞的,通道可以异步读写。 |
选择器(Selector) | Selector可以称他为通道的集合,每次客户端来了之后我们会把Channel注册到Selector中并且我们给他一个状态,在用死循环来判断状态是否发生变化,判断是否做完某个操作,完成某个操作后改变不一样的状态,知道IO操作完成后在退出死循环。 |
缓冲区(Buffer) | Buffer是一个缓冲数据的对象, 它包含一些要写入或者刚读出的数据。在普通的面向流的IO中,一般将数据直接写入或直接读到Stream对象中。当是有了Buffer缓冲区后,数据第一步到达的是Buffer缓冲区中。缓冲区实质上是一个数组,底层完全是数组实现的。通常它是一个字节数组,内部维护几个状态变量,可以实现在同一块缓冲区上反复读写,不用清空数据再写。 |
BIO与NIO
BIO是阻塞的,NIO是非阻塞的。BIO是面向流的,只能单向读写,NIO是面向缓冲的, 可以双向读写。使用BIO做Socket连接时,由于单向读写,当没有数据时,会挂起当前线程,阻塞等待,为防止影响其它连接,需要为每个连接新建线程处理,然而系统资源是有限的,不能过多的新建线程,线程过多带来线程上下文的切换,从来带来更大的性能损耗,因此需要使用NIO进行BIO多路复用,使用一个线程来监听所有Socket连接,使用本线程或者其他线程处理连接。AIO是非阻塞以异步方式发起IO操作。当IO操作进行时可以去做其他操作,由操作系统内核空间提醒IO操作已完成。NIO和BIO有着相同的目的和作用,但是它们的实现方式完全不同,BIO以流的方式处理数据,而NIO以块的方式处理数据,块IO的效率比流IO高很多。另外,NIO是非阻塞式的,这一点跟BIO也很不相同,使用它可以提供非阻塞式的高伸缩性网络。NIO主要有三大核心部分:Channel(通道)、Buffer(缓冲区)、Selector(选择器)。传统的BIO基于字节流和字符流进行操作,而NIO基于Channel(通道)和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。Selector(选择区)用于监听多个通道的事件(比如:连接请求,数据到达等),因此使用单个线程就可以监听多个客户端通道。
BIO图示:
NIO图示:
客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有IO请求时才启动一个线程进行处理。NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂。
网络IO模型
阻塞BIO
同步阻塞BIO(blocking IO):A拿着一支鱼竿在河边钓鱼,并且一直在鱼竿前等,在等的时候不做其他的事情,十分专心。只有鱼上钩的时,才结束掉等的动作,把鱼钓上来。在内核将数据准备好之前,系统调用会一直等待所有的套接字,默认的是阻塞方式。其中用户空间就是应用程序空间,由于我们的应用程序是不能直接访问硬盘的,我们程序没有权限直接访问,但是操作系统(Windows、Linux…)会给我们一部分权限较高的内存空间,他就叫内核空间,和我们的实际硬盘空间是有区别的。
非阻塞NIO
同步非阻塞NIO(noblocking IO):B也在河边钓鱼,但是B不想将自己的所有时间都花费在钓鱼上,在等鱼上钩这个时间段中,B也在做其他的事情(一会看看书,一会读读报纸,一会又去看其他人的钓鱼等),但B在做这些事情的时候,每隔一个固定的时间检查鱼是否上钩。一旦检查到有鱼上钩,就停下手中的事情,把鱼钓上来。B在检查鱼竿是否有鱼,是一个轮询的过程。
异步AIO
异步非阻塞AIO(asynchronous IO):C也想钓鱼,但C有事情,于是他雇来了D、E、F让他们帮他等待鱼上钩,一旦有鱼上钩,就打电话给C,C就会将鱼钓上去。当应用程序请求数据时,内核一方面去取数据报内容返回,另一方面将程序控制权还给应用进程,应用进程继续处理其他事情,是一种非阻塞的状态。
信号驱动IO
信号驱动IO(signal blocking I/O):G也在河边钓鱼,但与A、B、C不同的是,G比较聪明,他给鱼竿上挂一个铃铛,当有鱼上钩的时候,这个铃铛就会被碰响,G就会将鱼钓上来。信号驱动IO模型,应用进程告诉内核:当数据报准备好的时候,给我发送一个信号,对SIGIO信号进行捕捉,并且调用我的信号处理函数来获取数据报。
IO多路转接
IO多路转接(I/O multiplexing):H同样也在河边钓鱼,但是H生活水平比较好,H拿了很多的鱼竿,一次性有很多鱼竿在等,H不断的查看每个鱼竿是否有鱼上钩。增加了效率,减少了等待的时间。IO多路转接是多了一个select函数,select函数有一个参数是文件描述符集合,对这些文件描述符进行循环监听,当某个文件描述符就绪时,就对这个文件描述符进行处理。IO多路转接是属于阻塞IO,但可以对多个文件描述符进行阻塞监听,所以效率较高。
网络协议
TCP/IP、UDP基础
TCP/IP:传输控制/网络协议,是面向连接的协议,发送数据前要先建立连接(发送方和接收方的成对的两个之间必须建立连接),TCP提供可靠的服务,也就是说,通过TCP连接传输的数据不会丢失,没有重复,并且按顺序到达。传输控制协议/因特网互联协议,是Internet最基本、最广泛的协议;定义了计算机如何连如因特网,以及数据传输的标准。它采用四层模型,由下至上为:数据链路层/物理层》》网络层》》传输层》》应用层。
UDP:它是属于TCP/IP协议族中的一种。是无连接的协议,发送数据前不需要建立连接,是没有可靠性的协议。因为不需要建立连接所以可以在在网络上以任何可能的路径传输,因此能否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的。
对某些实时性要求比较高的情况使用UDP,比如游戏、媒体通信、实时直播,即使出现传输错误也可以容忍;其它大部分情况下,HTTP都是用TCP,因为要求传输的内容可靠,不出现丢失的情况。
运行在TCP或UDP的应用层协议
运行在TCP协议上的协议:
HTTP(Hypertext Transfer Protocol,超文本传输协议),主要用于普通浏览。
HTTPS(HTTP over SSL,安全超文本传输协议),HTTP协议的安全版本。
FTP(File Transfer Protocol,文件传输协议),用于文件传输。
POP3(Post Office Protocol, version 3,邮局协议),收邮件用。
SMTP(Simple Mail Transfer Protocol,简单邮件传输协议),用来发送电子邮件。
TELNET(Teletype over the Network,网络电传),通过一个终端(terminal)登陆到网络。
SSH(Secure Shell,用于替代安全性差的TELNET),用于加密安全登陆用。
运行在UDP协议上的协议:
BOOTP(Boot Protocol,启动协议),应用于无盘设备。
NTP(Network Time Protocol,网络时间协议),用于网络同步。
DHCP(Dynamic Host Configuration Protocol,动态主机配置协议),动态配置IP地址。
运行在TCP和UDP协议上的协议:
DNS(Domain Name Service,域名服务),用于完成地址查找,邮件转发等工作。
ECHO(Echo Protocol,回绕协议),用于查错及测量应答时间(运行在TCP和UDP协议上)。
SNMP(Simple Network Management Protocol,简单网络管理协议),用于网络信息的收集和网络管理。
DHCP(Dynamic Host Configuration Protocol,动态主机配置协议),动态配置IP地址。
ARP(Address Resolution Protocol,地址解析协议),用于动态解析以太网硬件的地址。
TCP与UDP区别
1、TCP是面向连接的协议,发送数据前要先建立连接,TCP提供可靠的服务,也就是说,通过TCP连接传输的数据不会丢失,没有重复,并且按顺序到达。
2、UDP是无连接的协议,发送数据前不需要建立连接,是没有可靠性。
3、TCP通信类似于于要打个电话,接通了,确认身份后,才开始进行通行。
4、UDP通信类似于学校广播,靠着广播播报直接进行通信。
5、TCP只支持点对点通信,UDP支持一对一、一对多、多对一、多对多。
6、TCP是面向字节流的,UDP是面向报文的。面向字节流是指发送数据时以字节为单位,一个数据包可以拆分成若干组进行发送,而UDP一个报文只能一次发完。
7、TCP首部开销(20字节)比UDP首部开销(8字节)要大。
8、UDP的主机不需要维持复杂的连接状态表。
TCP的三次握手
在网络数据传输中,传输层协议TCP是要建立连接的可靠传输,TCP建立连接的过程,我们称为三次握手。
第一次握手:客户端向服务端发送SYN。Client将SYN置1,随机产生一个初始序列号seq发送给Server,进入SYN_SENT状态。
第二次握手:服务端返回SYN、ACK。Server收到Client的SYN=1之后,知道客户端请求建立连接,将自己的SYN置1,ACK置1,产生一个acknowledge number=sequence number+1,并随机产生一个自己的初始序列号,发送给客户端;进入SYN_RCVD状态。
第三次握手:客户端发送ACK。客户端检查acknowledge number是否为序列号+1,ACK是否为1,检查正确之后将自己的ACK置为1,产生一个acknowledge number=服务器发的序列号+1,发送给服务器;进入ESTABLISHED状态;服务器检查ACK为1和acknowledge number为序列号+1之后,也进入ESTABLISHED状态;完成三次握手,连接建立。
初始序列号:TCP连接的一方A,随机选择一个32位的序列号(Sequence Number)作为发送数据的初始序列号(Initial Sequence Number,ISN),比如为1000,以该序列号为原点,对要传送的数据进行编号:1001、1002…三次握手时,把这个初始序列号传送给另一方B,以便在传输数据时,B可以确认什么样的数据编号是合法的;同时在进行数据传输时,A还可以确认B收到的每一个字节,如果A收到了B的确认编号(acknowledge number)是2001,就说明编号为1001-2000的数据已经被B成功接受。
不能二次握手,可以多次握手
第一次握手:客户什么都不能确认;服务器确认了对方发送正常。
第二次握手:客户确认了:自己发送、接收正常,对方发送、接收正常;服务器确认了:自己接收正常,对方发送正常。
第三次握手:客户确认了:自己发送、接收正常,对方发送、接收正常;服务器确认了:自己发送、接收正常,对方发送接收正常。
所以三次握手就能确认双发收发功能都正常,缺一不可。由于可能会出现已失效的连接请求报文段又传到了服务器端的情况。大于客户端发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达服务端。本来这是一个早已失效的报文段。但服务端收到此失效的连接请求报文段后,就误认为是客户端再次发出的一个新的连接请求。于是就向客户端发出确认报文段,同意建立连接。假设不采用三次握手而是二次或更少握手,那么只要服务端发出确认,新的连接就建立了。由于现在客户端并没有发出建立连接的请求,因此不会理睬服务端的确认,也不会向服务端发送数据。但服务端却以为新的运输连接已经建立,并一直等待客户端发来数据。这样,服务端的很多资源就白白浪费掉了。采用三次握手的办法可以防止上述现象发生。例如刚才那种情况,客户端不会向服务端的确认发出确认。服务端由于收不到确认,就知道客户端并没有要求建立连接。而且,两次握手无法保证客户端正确接收第二次握手的报文(服务端无法确认客户端是否收到),也无法保证客户端和服务端之间成功互换初始序列号。总的来说,就是服务端确认收到了客户端请求并返回确认给客户端,但是没有第三次握手,客户端就不会再正式的发请求给服务端。当然,三次握手都可以保证连接成功了,所以四次或更多已经无所谓了,但是会降低传输的效率。
第三次握手中,如果客户端的ACK未送达服务器
Server端:由于Server没有收到ACK确认,因此会每隔3秒重发之前的SYN+ACK(默认重发五次,之后自动关闭连接进入CLOSED状态),Client收到后会重新传ACK给Server。
Client端,会出现两种情况:
1、在Server进行超时重发的过程中,如果Client向服务器发送数据,数据头部的ACK是为1的,所以服务器收到数据之后会读取ACK number,进入establish状态。
2、在Server进入CLOSED状态之后,如果Client向服务器发送数据,服务器会以RST包应答。
建立连接之后客户端出现了故障
服务器每收到一次客户端的请求后都会重新复位一个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
TCP的四次挥手
在网络数据传输中,传输层协议断开连接的过程我们称为四次挥手。
第一次挥手:Client将FIN置为1,发送一个序列号seq给Server;进入FIN_WAIT_1状态。
第二次挥手:Server收到FIN之后,发送一个ACK=1,acknowledge number=收到的序列号+1;进入CLOSE_WAIT状态。此时客户端已经没有要发送的数据了,但仍可以接受服务器发来的数据。
第三次挥手:Server将FIN置1,发送一个序列号给Client;进入LAST_ACK状态。
第四次挥手:Client收到服务器的FIN后,进入TIME_WAIT状态;接着将ACK置1,发送一个acknowledge number=序列号+1给服务器;服务器收到后,确认acknowledge number后,变为CLOSED状态,不再向客户端发送数据。客户端等待2*MSL(报文段最长寿命)时间后,也进入CLOSED状态。完成四次挥手。
四次挥手断开连接是因为要确定数据全部传输完了:
客户与服务器交谈结束之后,客户要结束此次会话,就会对服务器说:我要关闭连接了(第一次挥手)
服务器收到客户的消息后说:好的,你要关闭连接了。(第二次挥手)
然后服务器确定了没有话要和客户说了,服务器就会对客户说,我要关闭连接了。(第三次挥手)
客户收到服务器要结束连接的消息后说:已收到你要关闭连接的消息(第四次挥手),才关闭。
不能三次挥手
不能把服务器发送的ACK和FIN合并起来,变成三次挥手(CLOSE_WAIT状态意义):因为服务器收到客户端断开连接的请求时,可能还有一些数据没有发完,这时先回复ACK,表示接收到了断开连接的请求。等到数据发完之后再发FIN,断开服务器到客户端的数据传送。如果第二次挥手时服务器的ACK没有送达客户端,会重新发送FIN请求。
TIME_WAIT状态意义
第四次挥手时,客户端发送给服务器的ACK有可能丢失,TIME_WAIT状态就是用来重发可能丢失的ACK报文。如果Server没有收到ACK,就会重发FIN,如果Client在2MSL的时间内收到了FIN,就会重新发送ACK并再次等待2MSL,防止Server没有收到ACK而不断重发FIN。MSL(Maximum Segment Lifetime),指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。
Socket基础
Socket简介
Socket其实并不是一个协议,而是为了方便使用TCP或UDP而抽象出来的一层,是应用层与TCP/IP协议族通信的中间软件抽象层,是位于应用层和传输控制层之间的一组接口。在设计模式中,Socket是一个外观模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。当两台主机通信时,必须通过Socket连接,Socket则利用TCP/IP协议建立TCP连接。TCP连接则更依靠于底层的IP协议,IP协议的连接则依赖于链路层等更低层次。Socket通讯的过程:
基于TCP:服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。
基于UDP:UDP协议是用户数据报协议的简称,也用于网络数据的传输。虽然UDP协议是一种不太可靠的协议,但有时在需要较快地接收数据并且可以忍受较小错误的情况下,UDP就会表现出更大的优势。我客户端只需要发送,服务端能不能接收的到我不管。
Socket常用类
类名 | 协议 | 说明 |
---|---|---|
Socket | TCP协议 | Socket类同时工作于客户端和服务端,所有方法都是通用的,这个类三个主要作用,校验包信息,发起连接(Client),操作流数据(Client/Server)。 |
ServerSocket | TCP协议 | ServerSocket表示为服务端,主要作用就是绑定并监听一个服务器端口,为每个建立连接的客户端“克隆/映射”一个Socket对象,具体数据操作都是通过这个Socket对象完成的,ServerSocket只关注如何和客户端建立连接。 |
DatagramSocket | ODP协议 | DatagramSocket类用于表示发送和接收数据报包的套接字。 |
DatagramPacket | ODP协议 | DatagramPacket类用来表示数据报包,数据报包用来实现无连接包投递服务。 |
InetAddress | IP+端口号 | Java提供了InetAddress类来代表互联网协议(IP)地址,InetAddress类没有提供构造器,而是提供了两个静态方法来获取InetAddress实例。 |
InetSocketAddress | IP+端口号 | 在使用Socket来连接服务器时最简单的方式就是直接使用IP和端口,但Socket类中并未提供这种方式,而是靠SocketAddress的子类InetSocketAddress来实现IP地址+端口号的创建,不依赖任何协议。 |
WebSocket简介
Socket是传输控制层协议,WebSocket则是一个典型的应用层协议。B/S结构的软件项目中有时客户端需要实时的获得服务器消息,但默认HTTP协议只支持请求响应模式,这样做可以简化Web服务器,减少服务器的负担,加快响应速度,因为服务器不需要与客户端长时间建立一个通信链接,但不容易直接完成实时的消息推送功能,如聊天室、后台信息提示、实时更新数据等功能,但通过polling、Long polling、长连接、Flash Socket以及HTML5中定义的WebSocket能完成该功能需要。WebSocket是HTML5开始提供的一种浏览器与服务器间进行全双工通讯的网络技术。依靠这种技术可以实现客户端和服务器端的长连接,双向实时通信。特点:事件驱动、异步、使用ws或者wss协议的客户端Socket、能够实现真正意义上的推送功能。缺点:少部分浏览器不支持,浏览器支持的程度与方式有区别。WebSocket的url开头是ws,如果需要ssl加密可以使用wss,当我们调用WebSocket的构造方法构建一个WebSocket对象(new WebSocket(url))之后,就可以进行即时通信了。
HTTP基础
HTTP简介
HTTP(Hyper Text Transfer Protocol)概念:HTTP协议是对客户端和服务器端之间数据之间实现可靠性的传输文字、图片、音频、视频等超文本数据的规范,格式简称为超文本传输协议。HTTP协议属于应用层,及用户访问的第一层就是HTTP。HTTP是一个简单的请求响应协议,它通常运行在TCP之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。请求和响应消息的头以ASCII码形式给出;而消息内容则具有一个类似MIME的格式。这个简单模型是早期Web成功的有功之臣,因为它使得开发和部署是那么的直截了当。特点总结:基于TCP/IP的高级协议、默认端口号是80、一次请求对应一次响应、无状态:每次请求之间相互独立,不能交互数据。
HTTP版本
HTTP1.0版本的特性:早先1.0的HTTP版本,是一种无状态、无连接的应用层协议。HTTP1.0规定浏览器和服务器保持短暂的连接,浏览器的每次请求都需要与服务器建立一个TCP连接,服务器处理完成后立即断开TCP连接(无连接),服务器不跟踪每个客户端也不记录过去的请求(无状态)。
HTTP1.1版本新特性:默认持久连接节省通信量,只要客户端服务端任意一端没有明确提出断开TCP连接,就一直保持连接,可以发送多次HTTP请求。管线化,客户端可以同时发出多个HTTP请求,而不用一个个等待响应。断点续传原理。
HTTP2.0版本的特性:二进制分帧(采用二进制格式的编码将其封装)、首部压缩(设置了专门的首部压缩设计的HPACK算法)、流量控制(设置了接收某个数据流的多少字节一些流量控制)、多路复用(可以在共享TCP链接的基础上同时发送请求和响应)、请求优先级(可以通过优化这些帧的交错和传输顺序进一步优化性能)、服务器推送(就是服务器可以对一个客户端请求发送多个响应。服务器向客户端推送资源无需客户端明确的请求。这是一个重大更新)。
HTTP请求
HTTP请求报文由四个部分组成:请求行、请求头、请求空行、请求体
请求行
请求行由请求方法字段、URL字段和HTTP协议版本字段3个字段组成,它们用空格分隔。比如 GET /data/info.html HTTP/1.1,方法字段就是HTTP使用的请求方法,比如常见的GET/POST。请求行案例:
Request URL: http://localhost:8099/chat.html
Request Method: GET
Status Code: 200
Remote Address: [::1]:8099
Referrer Policy: no-referrer-when-downgrade
请求头
HTTP客户程序(例如浏览器),向服务器发送请求的时候必须指明请求类型(一般是GET或者POST)。如有必要,客户程序还可以选择发送其他的请求头。大多数请求头并不是必需的,但Content-Length除外。对于POST请求来说Content-Length必须出现。常见的请求头字段含义:
名称 | 含义 |
---|---|
Accept | 浏览器可接受的MIME类型 |
Accept-Charset | 浏览器可接受的字符集 |
Accept-Encoding | 浏览器能够进行解码的数据编码方式,比如gzip。Servlet能够向支持gzip的浏览器返回经gzip编码的HTML页面。许多情形下这可以减少5到10倍的下载时间。 |
Accept-Language | 浏览器所希望的语言种类,当服务器能够提供一种以上的语言版本时要用到 |
Authorization | 授权信息,通常出现在对服务器发送的WWW-Authenticate头的应答中 |
Content-Length | 表示请求消息正文的长度 |
Host | 客户机通过这个头告诉服务器,想访问的主机名。Host头域指定请求资源的Intenet主机和端口号, 必须表示请求url的原始服务器或网关的位置。HTTP/1.1请求必须包含主机头域,否则系统会以400状态码返回。 |
If-Modified-Since | 客户机通过这个头告诉服务器,资源的缓存时间。只有当所请求的内容在指定的时间后又经过修改才返回它,否则返回304“Not Modified”应答。 |
Referer | 客户机通过这个头告诉服务器,它是从哪个资源来访问服务器的(防盗链)。 包含一个URL,用户从该URL代表的页面出发访问当前请求的页面。 |
User-Agent | User-Agent头域的内容包含发出请求的用户信息。 浏览器类型,如果Servlet返回的内容与浏览器类型有关则该值非常有用。 |
Cookie | 客户机通过这个头可以向服务器带数据,这是最重要的请求头信息之一 |
Pragma | 指定“no-cache”值表示服务器必须返回一个刷新后的文档,即使它是代理服务器而且已经有了页面的本地拷贝。 |
From | 请求发送者的email地址,由一些特殊的Web客户程序使用,浏览器不会用到它。 |
Connection | 处理完这次请求后是否断开连接还是继续保持连接。 如果Servlet看到这里的值为“Keep- Alive”,或者看到请求使用的是HTTP 1.1(HTTP 1.1默认进行持久连接),它就可以利用持久连接的优点,当页面包含多个元素时(例如Applet,图片),显著地减少下载所需要的时间。 要实现这一点,Servlet需要在应答中发送一个Content-Length头,最简单的实现方法是:先把内容写入 ByteArrayOutputStream,然后在正式写出内容之前计算它的大小。 |
Range | Range头域可以请求实体的一个或者多个子范围。例如, 表示头500个字节:bytes=0-499 表示第二个500字节:bytes=500-999 表示最后500个字节:bytes=-500 表示500字节以后的范围:bytes=500- 第一个和最后一个字节:bytes=0-0,-1 同时指定几个范围:bytes=500-600,601-999 但是服务器可以忽略此请求头,如果无条件GET包含Range请求头,响应会以状态码206(PartialContent)返回而不是以200 (OK)。 |
UA-Pixels,UA-Color,UA-OS,UA-CPU | 由某些版本的IE浏览器所发送的非标准的请求头,表示屏幕大小、颜色深度、操作系统和CPU类型。 |
请求头案例:
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cache-Control: no-cache
Connection: keep-alive
Cookie: username=admin; rememberMe=true; password=zAtnodd6JmAq/7mclukdAFuNrB6x0wEd3dsjLW09Co6E3jrkhsnTi/sVmPXShoUbJzDLfPGD2hoLgjbiliCsig==
Host: localhost:8099
Pragma: no-cache
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36
请求空行
它的作用是通过一个空行,告诉服务器请求头部到此为止。
请求体
若方法字段是GET,则此项为空,没有数据,若方法字段是POST,则通常来说此处放置的就是要提交的数据。比如要使用POST方法提交一个表单,其中有user字段中数据为“admin”,password字段为123456,那么这里的请求数据就是user=admin&password=123456,使用&来连接各个字段。POST方法,它的请求行URL段中一般是没有参数的,参数放在了请求体中。而GET方法的参数直接置于请求行URL中,请求体则为空。请求体案例:
user:admin
password:123456
请求方式
GET:用于请求访问已经被URI(统一资源标识符)识别的资源,可以通过URL传参给服务器。
POST:用于传输信息给服务器,主要功能与GET方法类似,但一般推荐使用POST方式。
PUT:传输文件,报文主体中包含文件内容,保存到对应URI位置。
HEAD:获得报文首部,与GET方法类似,只是不返回报文主体,一般用于验证URI是否有效。
PATCH:客户端向服务器传送的数据取代指定的文档的内容(部分取代)。
TRACE:回显客户端请求服务器的原始请求报文,用于"回环"诊断。
DELETE:删除文件,与PUT方法相反,删除对应URI位置的文件。
OPTIONS:查询相应URI支持的HTTP方法。
GET与POST
GET方法与POST方法的区别:
1)Get重点在从服务器上获取资源,Post重点在向服务器发送数据。
2)Get传输的数据量小,因为受URL长度限制,但效率较高;Post可以传输大量数据,所以上传文件时只能用Post方式。
3)Get是不安全的,因为Get请求发送数据是在URL上,是可见的,可能会泄露私密信息,如密码等;Post是放在请求体的,是相对安全的。
一次完整的HTTP请求
HTTP通信机制是在一次完整的HTTP通信过程中,Web浏览器与Web服务器之间将完成下列7个步骤:
1)建立TCP连接(三次握手)
2)Web浏览器向Web服务器发送请求行,一旦建立了TCP连接,Web浏览器就会向Web服务器发送请求命令。例如:GET /sample/hello.jsp HTTP/1.1。
3)Web浏览器发送请求头,浏览器发送其请求命令之后,还要以头信息的形式向Web服务器发送一些别的信息,之后浏览器发送了一空白行来通知服务器,它已经结束了该头信息的发送。
4)Web服务器应答,客户机向服务器发出请求后,服务器会客户机回送应答,HTTP/1.1 200 OK ,应答的第一部分是协议的版本号和应答状态码。
5)Web服务器发送应答头,正如客户端会随同请求发送关于自身的信息一样,服务器也会随同应答向用户发送关于它自己的数据及被请求的文档。
6)Web服务器向浏览器发送数据,Web服务器向浏览器发送头信息后,它会发送一个空白行来表示头信息的发送到此为结束,接着,它就以Content-Type应答头信息所描述的格式发送用户所请求的实际数据。
7)Web服务器关闭TCP连接
HTTP响应
HTTP响应报文由三部分组成:响应行、响应头、响应体
响应行
响应行一般由协议版本、状态码及其描述组成,比如HTTP/1.1 200 OK,其中协议版本HTTP/1.1或者HTTP/1.0,200就是它的状态码,OK则为它的描述。
响应头
响应头用于描述服务器的基本信息,以及数据的描述,服务器通过这些数据的描述信息,可以通知客户端如何处理等一会儿它回送的数据。设置HTTP响应头往往和状态码结合起来。例如,有好几个表示“文档位置已经改变”的状态代码都伴随着一个Location头,而401(Unauthorized)状态代码则必须伴随一个WWW-Authenticate头。然而,即使在没有设置特殊含义的状态代码时,指定应答头也是很有用的。应答头可以用来完成:设置Cookie,指定修改日期,指示浏览器按照指定的间隔刷新页面,声明文档的长度以便利用持久HTTP连接等等许多其他任务。常见的响应头字段含义:
名称 | 含义 |
---|---|
Allow | 服务器支持哪些请求方法(如GET、POST等) |
Content-Encoding | 文档的编码(Encode)方法。只有在解码之后才可以得到Content-Type头指定的内容类型。 利用gzip压缩文档能够显著地减少HTML文档的下载时间。Java的GZIPOutputStream可以很方便地进行gzip压缩,但只有Unix上的Netscape和Windows上的IE4、IE5才支持它。因此,Servlet应该通过查看Accept-Encoding头(即request.getHeader(“Accept- Encoding”))检查浏览器是否支持gzip,为支持gzip的浏览器返回经gzip压缩的HTML页面,为其他浏览器返回普通页面。 |
Content-Length | 表示内容长度。只有当浏览器使用持久HTTP连接时才需要这个数据。 如果你想要利用持久连接的优势,可以把输出文档写入 ByteArrayOutputStram,完成后查看其大小,然后把该值放入Content-Length头,最后通过byteArrayStream.writeTo(response.getOutputStream()发送内容。 |
Content-Type | 表示后面的文档属于什么MIME类型。Servlet默认为text/plain,但通常需要显式地指定为text/html。由于经常要设置 Content-Type,因此HttpServletResponse提供了一个专用的方法setContentType。 |
Date | 当前的GMT时间,例如,Date:Mon,31Dec200104:25:57GMT。 Date描述的时间表示世界标准时,换算成本地时间,需要知道用户所在的时区。你可以用setDateHeader来设置这个头以避免转换时间格式的麻烦。 |
Expires | 告诉浏览器把回送的资源缓存多长时间,-1或0则是不缓存。 |
Last-Modified | 文档的最后改动时间。客户可以通过If-Modified-Since请求头提供一个日期,该请求将被视为一个条件GET,只有改动时间迟于指定时间的文档才会返回,否则返回一个304(Not Modified)状态。Last-Modified也可用setDateHeader方法来设置。 |
Location | 这个头配合302状态码使用,用于重定向接收者到一个新URI地址。表示客户应当到哪里去提取文档。 Location通常不是直接设置的,而是通过HttpServletResponse的sendRedirect方法,该方法同时设置状态代码为302。 |
Refresh | 告诉浏览器隔多久刷新一次,以秒计。 |
Server | 服务器通过这个头告诉浏览器服务器的类型。Server响应头包含处理请求的原始服务器的软件信息。 此域能包含多个产品标识和注释,产品标识一般按照重要性排序。Servlet一般不设置这个值,而是由Web服务器自己设置。 |
Set-Cookie | 设置和页面关联的Cookie。Servlet不应使用response.setHeader(“Set-Cookie”, …),而是应使用HttpServletResponse提供的专用方法addCookie。 |
Transfer-Encoding | 告诉浏览器数据的传送格式 |
WWW-Authenticate | 客户应该在Authorization头中提供什么类型的授权信息,在包含401(Unauthorized)状态行的应答中这个头是必需的。 例如,response.setHeader(“WWW-Authenticate”, “BASIC realm=\”executives\”“)。注意Servlet一般不进行这方面的处理,而是让Web服务器的专门机制来控制受密码保护页面的访问。 |
注:设置应答头最常用的方法是HttpServletResponse的setHeader,该方法有两个参数,分别表示应答头的名字和值。和设置状态代码相似,设置应答头应该在发送任何文档内容之前进行。setDateHeader方法和setIntHeadr方法专门用来设置包含日期和整数值的应答头,前者避免了把Java时间转换为GMT时间字符串的麻烦,后者则避免了把整数转换为字符串的麻烦。HttpServletResponse还提供了许多其他设置:
setContentType:设置Content-Type头,大多数Servlet都要用到这个方法。
setContentLength:设置Content-Length头,对于支持持久HTTP连接的浏览器来说,这个函数是很有用的。
addCookie:设置一个Cookie(Servlet API中没有setCookie方法,因为应答往往包含多个Set-Cookie头)。
响应体
响应体就是响应的消息体,如果是纯数据就是返回纯数据,如果请求的是HTML页面,那么返回的就是HTML代码,如果是JS就是JS代码,如此之类。
响应状态码
状态码类别:
100~199:表示成功接收请求,要求客户端继续提交下一次请求才能完成整个处理过程。
200~299:表示成功接收请求并已完成整个处理过程。常用200
300~399:为完成请求,客户需进一步细化请求。例如:请求的资源已经移动一个新地址、
常用302(意味着你请求我,我让你去找别人),307和304(我不给你这个资源,自己拿缓存)
400~499:客户端的请求有错误,常用404(意味着你请求的资源在web服务器中没有)403(服务器拒绝访问,权限不够)
500~599:服务器端出现错误,常用500
具体状态码详解:
200:请求被正常处理
204:请求被受理但没有资源可以返回
206:客户端只是请求资源的一部分,服务器只对请求的部分资源执行GET方法,相应报文中通过Content-Range指定范围的资源
301:永久性重定向
302:临时重定向
303:与302状态码有相似功能,只是它希望客户端在请求一个URI的时候,能通过GET方法重定向到另一个URI上
304:发送附带条件的请求时,条件不满足时返回,与重定向无关
307:临时重定向,与302类似,只是强制要求使用POST方法
400:请求报文语法有误,服务器无法识别
401:请求需要认证
403:请求的对应资源禁止被访问
404:服务器无法找到对应资源
500:服务器内部错误
503:服务器正忙
HTTPS基础
HTTP、HTTPS
其实HTTPS就是从HTTP加上加密处理(一般是SSL安全通信线路)+认证+完整性保护。主要区别如下:
1)HTTPS需要拿到CA证书,需要用钱购买。
2)默认端口不一样,HTTP是80,HTTPS是443。
3)HTTP是超文本传输协议,信息是明文传输,HTTPS则是具有安全性的ssl加密传输协议。
4)HTTP和HTTPS使用的是完全不同的连接方式(HTTP的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比HTTP协议安全。)
5)HTTP协议是由明文传输的,因此会带来三大风险:
被窃听的风险:第三方可以截获查看你请求的内容
被篡改的风险:第三方可以修改你请求的内容
被冒充的风险:第三方可以伪装成通信方与你通信
HTTPS工作原理
问题呈现,A对B发送消息,C截取:
1)A、B只采用内容对称加密(同一个秘钥),会存在秘钥被C截取,导致C也能看见自己的内容并且篡改。
2)A、B采用对内容(该内容已对称加密)非对称加密(私钥和公钥),公钥会被截取,A发送给别人的对称秘钥可以被C获取的公钥解密看见,但是无法篡改,因为只有A的私钥可以加密,否则B也解不开(这也是一种身份认证,说明发送者是A);然后B发送给A的C无法看见,因为只有A的私钥可以解密。
3)中间人攻击:上面看似安全,其实C可以将自己的公钥给B,结果B用C的公钥加密了内容,发送的时候C可以通过自己的私钥解密查看,看完之后再通过A的公钥进行加密给A。结果2边的内容又被看见了。
4)所以上面的问题应该解决公钥如何不被C获取,最终可以通过CA机构获取A的公钥,保证安全。CA通过数字证书的方式解决公钥传输问题(数字证书就是解决公钥传输问题的)。
5)保证信息完整性(保证不被篡改):md5对信息加密,得到一个字符串,叫做摘要。A将md5算法和摘要一起发送,B通过md5对信息加密,然后比对摘要就能知道信息是否篡改。但是C还是可以获取之后生成摘要发送给B。所以需要A用自己的私钥对摘要进行加密,生成一个字符串叫签名,这样B解密签名,再用md5对内容进行加密,如果2次结果一致则没有被篡改。
6)数字证书是由CA机构颁发的,首先A如果想要有一个数字证书,就需要向CA机构申请,CA机构就会给A颁发一张数字证书,里面包含了:公钥:A的公钥、颁发者:CA(证书认证机构)、有效期:证书的使用期限、摘要算法:指定的摘要算法,用来计算证书的摘要、指纹:也就是证书的摘要,保证证书的完整性、签名算法:用于生成签名,确保证书是由CA签发、序列号:证书的唯一标识。如果有了证书,就不用公开传输公钥了,C也就无法获取。
7)最终A通过发送摘要算法(如md5)、摘要、签名、数字证书给B,B用自己的CA数字证书拿到CA公钥然后验证证书是CA颁发(验证证书没有被修改),最后获取到A的公钥进行安全通信。
访问www.helloworld.net的过程,阶段如下:
1)网站申请证书阶段
网站向CA机构申请数字证书(需要提交一些材料,比如域名)
CA向证书中写入摘要算法,域名,网站的公钥等重要信息
CA根据证书中写入的摘要算法,计算出证书的摘要
CA用自己的私钥对摘要进行加密,计算出签名
CA生成一张数字证书,颁发给www.helloworld.net
网站的管理员,把证书放在自己的服务器上
2)浏览器验证证书阶段
浏览器在地址栏中输入https://www.helloworld.net,并回车
服务器将数字证书发送给浏览器
浏览器用操作系统内置的CA的数字证书,拿到CA的公钥
浏览器用CA公钥对www.helloworld.net的数字证书进行验签
具体就是,浏览器用CA公钥,对helloworld的数字证书中的签名进行解密,得到摘要D1
浏览器根据helloworld数字证书中的摘要算法,计算出证书的摘要D2
对比D1和D2是否相等。
如果不相等,说明证书被掉包了
如果相等,说明证书验证通过了。
3)协商对称加密密钥阶段
浏览器验证数字证书通过以后
浏览器拿到数字证书中的公钥,也就是www.helloworld.net网站的公钥
浏览器有了网站的公钥后,就用公钥进行对密钥S进行加密,加密以后的密文发送给服务器
服务器收到密文后,用自己的私钥进行解密,得到密钥S
此后浏览器,服务器双方就用密钥S进行对称加密的通信了。
会话跟踪
Cookie
1)Cookie是由Web服务器保存在用户浏览器上的文件(key-value格式),可以包含用户相关的信息。客户端向服务器发起请求,就提取浏览器中的用户信息由HTTP发送给服务器。
2)Cookie生命周期:存储在客户端。如果不设置过期时间,则表示这个Cookie生命周期为浏览器会话期间,只要关闭浏览器窗口,Cookie就消失了。这种生命期为浏览会话期的Cookie被称为会话Cookie。会话Cookie一般不保存在硬盘上而是保存在内存里。如果设置了过期时间,浏览器就会把Cookie保存到硬盘上,关闭后再次打开浏览器,这些Cookie依然有效直到超过
设定的过期时间。存储在硬盘上的Cookie可以在不同的浏览器进程间共享,比如两个IE窗口。而对于保存在内存的Cookie,不同的浏览器有不同的处理方式。
3)Cookie过期时间设置
cookie.setMaxAge(int):设置为整数时,为多少秒过期。
cookie.setMaxAge(0):设置为0时,会马上在浏览器上删除指定的cookie。
cookie.setMaxAge(-1):设置为-1时,代表关闭当前浏览器即失效。
4)Cookie存储:tomcat8之前是不能直接在Cookie中存储中文,需要转码之后存储;tomcat8之后支持存储中文,但是不允许中文之间有空格。
5)Cookie共享数据:如果一个tomcat下部署多个web项目,他们之间是不能共享Cookie的;
可以设置Cookie的范围实现共享,setPath(String path),如:setPath("/")。不同的服务器之间的共享,需要设置setDomain(String path),如:setDomain(".baidu.com"),则tieba.baidu.com和news.baidu.com之间的Cookie可以共享。
Session
1)Session是浏览器和服务器会话过程中,服务器会分配的一块储存空间给Session。服务器默认为客户浏览器的Cookie中设置sessionid,这个sessionid就和Cookie对应,浏览器在向服务器请求过程中传输的Cookie包含sessionid ,服务器根据传输Cookie中的sessionid获取出会话中存储的信息,然后确定会话的身份信息。
2)Session的生命周期:存储在服务器端。一般放置在服务器的内存中(为了高速存取),Session在用户第一次访问服务器时创建,需要注意只有访问JSP、Servlet等程序时才会创建Session,只访问HTML、IMAGE等静态资源并不会创建Session,可调用request.getSession(true)强制生成Session。服务器会把长时间没有活动的Session从服务器内存中清除,此时Session便失效。Tomcat中Session的默认失效时间为20分钟;或者调用Session的invalidate方法使其失效。
3)Session的实现原理:第一次创建Session时,会将一个sessionId存入到Cookie中,然后将Cookie响应给浏览器,下次浏览器请求会把这个sessionId一起带入请求,获取到相应的Session。
Cookie与Session区别
Cookie特点
1)存储在客户端,安全性没有存储在服务器高
2)限制:浏览器对单个Cookie大小为4kb,以及同一个域名下Cookie数量为20个
3)一般存储不太敏感的数据;在登录时对身份进行验证
Session特点
1)浏览器关闭之后,服务器不关闭,下次打开浏览器获取的Session不是同一个,解决方式可以设置Cookie保存的JSessionId唯一。
2)浏览器不关闭,服务器重启,下次浏览器请求获取的Session不可能是同一个,这个问题tomcat可以自己持久化解决,但是在IDEA中配置的tomcat是不行的。
Cookie、Session区别
1)Cookie数据存放在客户端上,安全性较差,Session数据放在服务器上,安全性相对更高
2)单个Cookie保存的数据不能超过4K,Session无此限制
3)Session一定时间内保存在服务器上,当访问增多,占用服务器性能,考虑到服务器性能方面,应当使用Cookie。