1.谈谈http
首先要谈及的就是http协议,即超文本传输协议,这是一个应用层协议,由请求和响应组成,是一个标准的B/S模型,同时也是一个无连接的协议,这里的无连接是指每次只处理一个请求,同时也是一个无状态的协议,就是说,次请求和上一次下一次请求都没有任何关系。
大致的过程就是:建立连接—发送请求—响应—断开连接
一个http请求大致可分为:请求行,请求头和请求体,响应也一样,一般真正有用的数据都存放在请求体和响应体中。
2.谈谈https
其实https就是http的安全版,增加了一个SSL和TLS协议
SSL/TLS协议提供了加密的机制,所以比http加密更加安全,一般http的端口说80,https的端口是443
提供验证服务,验证本次会话实体身份的合法性。
提供加密服务,强加密机制能保证通话过程中的消息不会被破译
提供防篡改服务,利用hash算法对消息进行签名,通过验证签名保证通讯内容不被篡改。
https通讯一次做了哪些事情
1.客户端向服务区发送SSL/TLS协议版本,加密算法,产生的随机数,以及需要的各种信息。
2.服务器从客户端支持的加密算法中选择一组加密算法与hash算法,并且把自己的证书(包含网站地址,加密公钥,证书颁发机构等)发送给客户端
3.浏览器获取到服务区证书后验证其合法性,验证颁发机构是否合法,验证访问地址是否和正在访问的地址一致
4.浏览器生成一组随机数并用服务器传过来的公钥加密,再用约定好的hash算法计算握手消息,发送到服务端。
5.服务端接受到握手消息后,用自己的私钥解密,并且用hash算法验证,这样双方都有了此次通信的密钥。
6.服务器再使用密钥加密一段握手消息,返回给浏览器,
7.浏览器用密钥解密,并使用hash算法验证,确定算法以及密钥。
—-至此,就可以用协商好的密钥进行加密了通信了——
3.套接字通信
套接字通信是应用层与TCP/IP协议族通信的中间抽象层,他是一组接口,应用层通过调用这些接口发送和接收数据,一般这种抽象层是由操作系统提供或者由JVM自己实现。
位于传输层和应用层之间。
服务端套接字
1.创建ServerSocket实例,传入端口号等待阻塞。
2.初始化底层的socket并将进行监听。
3.创建socket底层数据结构,socket初始状态为关闭。
4.填入应用层传入的端口号,并设置socket状态为监听。
5.服务端开始监听客户端的访问。
6.客户端访问的时候经过三次握手完成连接,准备接收socket连接
7.为该连接创建一个新的套接字数据结构,根据到来的分组报文设置远端的端口以及IP,由于完成了三次握手,把状态设置为连接。
8.建立好连接的底层套接字数据结构会被放到一个队列缓冲区,提供应用层读取。
7.ServerSocket实例调用accept方法后,即开始轮询队列缓冲区,一旦队列中有新的连接则创建并返回一个应用层的socket实例。
8.如此工作直到关闭
客户端套接字
1.确定通信目标,包括目标端口以及ip
2.根据目标ip以及目标端口,在java应用层创建一个socket实例。
3.阻塞等待,准备进行系统底层相关工作。
4.创建socket底层数据结构,socket初始状态为关闭。
5.向这个socket填入本地、远程的地址和端口,并向远程服务器发送请求连接,此时的状态为正在连接
6.与远程服务器完成三次握手,此时状态为连接建立完成。
7.完成应用层上的socket实例化,对这个socket进行操作,实现通信。
注意:套接字存在缓冲,socket的写入并不是真正的写入,会存在操作系统的缓冲区,当超过缓冲区的大小,缓冲区会被一次性的读取。
一个通信demo
服务层:
ServerSocket serversocket = new ServerSocket(8888);
Socket socket = serverSocket.accept();
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
DataInputStream dis = new DataInputStream(socket.getInputStream());
System.out.println(“….”+dis.readUTF());
dos.writeUTF(“….”);
socket.close();
serverSocket.close();
客户端:
Socket socket = new Socket(“localhost”,8888);
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
DataInputStream dis = new DataInputStream(socket.getInputStream());
System.out.println(“….”+dis.readUTF());
dos.writeUTF(“….”);
socket.close();
不管是多么复杂的web容器,都是通过这样的建立起来的
单播通信:单个网络节点之间的通信,一对一的模式
组播通信:为了优化单播通信在某些场景下的不足,例如,一份数据要从某台主机发送到其余若干台主机上,这个时候如果还是使用单播通信的模式,数据必须依次发送给若干台主机,,当主机的数量越来越多的时候,可能会导致网络的阻塞,同时,这种方式效率太低。
广播通信:也是一对多的模式,他向所有主机都发送消息,不管主机是否需要,虽然浪费了网络资源,但是可以不用维护路由器与主机之间的成员关系
服务器模型:
1.单线程阻塞I/O模型:只有一个线程处理请求,模式是n:1,而阻塞I/O是指,读取数据要等待客户端发送数据并且把操作系统内核复制到用户进程中,这个时候才解除阻塞状态,写数据回客户端要等待用户进程将数据写入内核并发送到客户端后才解除阻塞。
2.多线程阻塞I/O:这个有多线程,但是I/O还是阻塞的,模式是1:1
3.单线程非阻塞I/O:当多个客户端向服务端请求的时候,服务端会保存一个套接字连接列表中,应用层线程对套接字列表轮询尝试读取与写入。对于读取操作,如果成功读取到若干数据,则对读取到的数据进行处理,如果读取失败,则在下一个循环继续尝试,写入也一样。
内核遍历套接字的事件监测:
服务器可以有多个客户端连接,应用层向内核请求读写事件列表,内核遍历所有套接字并生成对应的可读列表和可写列表,readList表明了每个套接字是否可读,例如套接字1的值为1,为可读,套接字2的值为0,为不可读
内核基于回调事件的事件监测:
当服务器有多个套接字连接,首先,应用层告诉内核每个套接字感兴趣的事件,接着当客户端发送数据过来的时候,对应会有一个回调函数,内核从网卡复制数据成功以后即调回调函数,将套接字1作为可读事件event1加入到事件列表当中去,同样,内核发现网卡可写的时候,就将套接字2作为可写事件event2添加到事件列表当中去,最后,应用层向内核请求读写事件列表,内核包含了event1,event2的事件列表返回应用层,应用层通过遍历事件知道,套接字1有数据待读取,而套接字2可写入。