ssskkk

通信协议的分层规定

把用户应用层作为最高层,把物理通信线路作为最底层,期间的协议处理分为若干层,规定每层处理的任务,也规定每层的接口标准。

目前分层国际的标准有两种:OSI参考模型和TCP/IP参考模型

一台机器想把一句话送出去的流程

需要从应用层一步步的把数据封装传递到最底层直到物理层的底层转换为二进制0100101010然后在送出去

送出去之后 对方最底层接收到0101010101然后一步步的翻译到应用层 这是数据在网络之间传输的一个过程。

底层对我们透明 看似是应用层之间通信,并不是。

HTTPS加密

在使用HTTPS时,所有的HTTP请求和响应数据在发送到网络之前,都要进行加密。

HTTPS在HTTP下面提供了一个传输级的密码安全层SSL/TSL(Transport Layer Security)。即在应用层和传输层之间加了一个安全层。

对称秘钥的加密技术:编/解码时使用相同秘钥的算法。

在对称加密技术中,发送端和接收端要共享相同的秘钥K才能进行通信。发送端用共享的秘钥加密报文,并将得到的密文发送给接收端。

接收端接收到密文,并对其应用解密函数和相同的共享秘钥,恢复出原始的明文。

对称秘钥加密技术的缺点之一就是发送者和接受者在互相对话之前,一定要有一个共享的保密秘钥。

流行的对称秘钥加密算法包括: DES Triple-DES RC2和RC4。64为的秘钥应该是大多数公司所采用的。

不对称秘钥加密系统:编/解码使用不同秘钥的算法。

非对称加密使用两个秘钥,一个用来对主机报文编码,另一个用来对主机报文解码。

编码秘钥是众所周知的,只有主机才知道私有的解密秘钥。

通过公开秘钥的加密技术,全球所有的计算机用户就都可以使用安全协议了,其中RSA算法是一个比较流行的公开秘钥的加密算法。

数字签名

数字签名是附加在报文上特殊加密校验码,使用数字签名有以下两个好处

  签名可以证明是作者编写了这条报文

  签名可以防止报文被篡改。如果有恶意攻击者在报文传输过程中对其进行了修改,校验和就不匹配了。

数字签名通常是用非对称公开秘钥技术产生的。因为只有所有者才知道其私有秘钥,所以可以将作者的私有秘钥当做一种指纹使用。

参考文章 https://blog.csdn.net/zmx729618/article/details/78485665

用证书对服务器进行认证。

通过HTTPS建立了一个安全的Web事物之后,浏览器都会自动获取所连接服务器的数字证书。

浏览器收到证书时,会对签名颁发机构进行检查。如果这个机构是个很有权威的公共签名机构,浏览器可以知道其公开秘钥了(浏览器会预装很多签名颁发机构的证书)。

参考文章 https://blog.csdn.net/zmx729618/article/details/78485665

Socket实现网络通信

启动一个TCPServer

public class TCPServer {
    public static void main(String[] args) throws Exception {
        ServerSocket ss = new ServerSocket(6666);
        while(true) {
            Socket s = ss.accept();
            System.out.println("a client connect!");
            DataInputStream dis = new DataInputStream(s.getInputStream());
            System.out.println(dis.readUTF());
            dis.close();
            s.close();
        }
    }
}
View Code

利用DataInputStream 的一些方法不需要把要读写的数据进行字节数组来回转换(inputStream只提供了读写字节和字节数组的方法).

通常数据输出流按照一定的格式输出,在通过数据输入流按照一定的格式输入,这样可以方便的对数据进行处理。

如:通过writeUTF()把一个Unicode字符串写进去,可以使用readUTF()直接读进来。

tip:String str = "abc";等效于: char data[] = {'a', 'b', 'c'}; String str = new String(data); 

启动一个TCPClient

public class TCPClient {
    public static void main(String[] args) throws Exception {
        Socket s = new Socket("127.0.0.1", 6666);
        OutputStream os = s.getOutputStream();
        DataOutputStream dos = new DataOutputStream(os);
        Thread.sleep(30000);
        dos.writeUTF("hello server!");
        dos.flush();
        dos.close();
        s.close();
    }
}
View Code

上面虽然实现了客户端与Server端的通信,但是缺点也很明显。

  • 在使用IO和Socket构造网络服务时 接收连接:accept(),接收请求数据,发送响应数据都可能引起阻塞的操作。、
  • 线程从Socket输入流读数据时,如果没有足够的数据就会进入阻塞状态,直到读够了足够的数据,或者达到输入流的末尾,或者出现了异常,才能从输入流的read()方法返回或异常中断。

输入流中有多少数据才算足够呢?这要看执行read()方法的类型。

  int read()只要输入流中有一个字节就算足够。

  int read(byte[] buff) 只要输入流中的字节数目与参数buff数组的长度相同,就算足够。(这个方法的好处 可以看看适配器设计模式中的知识点)

  String readLine() 只要输入流中有一行字符串就算足够(BufferReader类中才有此方法)。

Socket网络通信改进

以上两个阻塞式的方法住我们的当前线程。服务器可以使用多线程来处理阻塞I/O,尽管能满足同时响应多个客户请求的需求,但是增加了java虚拟机调度线程的负担。

在阻塞模式下,

  1. read()方法会争取读到n个字节,如果输入流中不足n个字节,就进入阻塞状态,直到读取了n个字节,或者读到了输入流末尾,或者出现了I/O异常。
  2. socket.accept()方法如果没有接收到连接,也会一直等待

在非阻塞模式下

  1. read()方法奉行能读到多少数据就读到多少数据的原则。read()方法读取当前通道中的可读数据,有可能不足n个字节,或者为0个字节,read()方法总会立刻返回。而不会等到读取了n个字节才返回,read()方法返回实际上读入的字节数。SocketChannel extends AbstractSelectableChannel 类的中 int read(ByteBuffer dst)方法是非阻塞式的。
  2. ServerSocketChannel或SockeChannel通过register()方法向Selector注册事件时,register()方法会创建一个SelectionKey对象,这个SelectionKey对象是跟踪注册事件的句柄。在SelectionKey对象有效期,Selector会一直监控与SelectorKey对象相关的事件,如果事件发生,就会把SelectionKey对象加入到Selector-keys集合中。

本文只是网络通信的扫盲篇,希望对java开发人员的面试有一些帮助。

相关文章: