美文网首页
远程通信协议原理

远程通信协议原理

作者: 剑道_7ffc | 来源:发表于2020-02-27 19:40 被阅读0次

    一个 http 请求的整个流程

    负责域名解析的 DNS 服务

    DNS服务提供通过域名来找到对应的ip,使用域名的原因是域名比ip地址更好记忆。


    image.png

    加速静态内容访问速度的 CDN

    CDN是一种内容分发网络(Content Delivery Network),将相对稳定的内容放在离用户最近的内容,这样做的好处是用户的访问速度会更快和节省整个广域网的消耗,我们一般会把静态的文件如图片,脚本和静态文件放在CDN中

    HTTP 协议通信原理

    HTTP是应用层协议,TCP/UDP是传输层的协议。


    image.png
    请求发起过程,在 tcp/ip 四层网络模型中所做的事情不停的封装如下图

    TCP头:根据端口号定位进程,用于点对点传输
    IP头:根据ip定位主机,用于段对端传输
    MAC头:根据mac地址定位网卡


    image.png

    注:目的mac地址的获取
    通过ARP(Adress Resolve Protocol)可以根据已知ip获取mac地址

    接收端收到数据包以后的处理过程不停的解封装如下图
    image.png

    注:为什么有了mac地址还需要ip
    mac地址表示人的身份证,全局唯一;
    IP地址表示一台机器在网络中的位置类似于城市名+道路号+门牌号

    TCP/IP 的分层管理

    分层的原因:降低复杂度和增加灵活性

    分层负载(OSI的七层模型)

    对于分层来讲,可以有下层没上层,但不可以没上层无下层如路由器。

    二层负载均衡

    针对的是MAC地址,特点:一个集群提供一个虚拟MAC地址,通过改写报文的目的MAC地址来请求到具体的服务器

    三层负载均衡

    针对的是IP,特点:一个集群提供一个虚拟ip,通过负载均衡算法来请求到具体的服务器

    四层负载均衡

    针对的是传输层(IP + 端口号),特点:一个集群提供一个虚拟ip,通过修改数据包的地址信息(IP + 端口号)来请求到具体的服务器

    七层负载均衡

    针对的是应用层,特点:通过虚拟的url或主机名来接受请求,然后在分配到具体的服务器

    TCP/IP 协议的深入分析

    TCP类似于打电脑,UDP协议类似于校园广播

    TCP 握手协议

    TCP的可靠性是连接的建立,通过三次握手来建立连接,即代码的connect的过程


    image.png

    ACK 可设为 1/0,1表示确认号有效,0表示确认号无效。
    SYN:用在连接建立的过程
    Seq:表示初始序号
    第一次:客户端发送完毕:客户端进入SYN_SEND 状态
    第二次:服务端发送完毕:服务端进入SYN_RCVD 状态
    第三次:客户端发送完毕:客户端进入ESTABLISHED状态
    服务端接受完毕:服务端进入ESTABLISHED状态

    SYN 攻击

    客户端伪造大量发送不存在的ip包(源ip),服务器确认,等待客户端的确认恢复,从而导致超时和正常的syn请求因队列满而被丢弃。

    TCP 四次挥手协议

    TCP协议是全双工的,对应的代码是客户端和服务端的close操作。


    image.png

    FIN:被用来释放连接,它表示发送方已经没有数据要传输了,但是可以继续接收数据
    第一次挥手:客户端发送完成:客户端进入 FIN_WAIT_1 状态
    第二次挥手:服务端发送完成:服务器端进入 CLOSE_WAIT 状态,客户端接收完成:客户端进入 FIN_WAIT_2 状态,服务端准备关闭
    第三次挥手:服务端发送完成:服务端进入LAST_ACK,服务端开始关闭
    第四次挥手:客户端发送完成:客户端进入TIME_WAIT,客户端在ZMSL的时间内,没有接收到ACK包,则自动进入CLOSED状态
    服务端接收完成:服务端进入CLOSED状态

    问题

    为什么连接的时候是三次握手,关闭的时候却是四次握手?

    三次握手是因为ACK和SYN可以一起发送;
    四次挥手是因为ACK和FIN不可以一起发送,第二次挥手表示对客户端的确认,但服务端关闭没有准备好,第三次挥手表示服务端关闭准备好了

    为什么 TIME_WAIT 状态需要经过 2MSL(最大报文段生存时间)才能返回到 CLOSE状态?

    因为网络是不可靠的,会导致最后一个ACK会出现丢失的情,从而引发服务端的超时重传。

    使用协议进行通信

    通过socket实现网络通信

    基于 TCP 协议实现通信

    客户端

        public static void main(String[] args)
        {
            Socket socket=null;
            PrintWriter out=null;
            try {
                socket=new Socket("127.0.0.1",8080);
                out=new PrintWriter(socket.getOutputStream(),true);
                out.println("Hello, Mic");
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if(out!=null){
                    out.close();
                }
                if(socket!=null){
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    

    服务端

        public static void main(String[] args)
                throws IOException {
            ServerSocket serverSocket = null;
            BufferedReader in = null;
            try {
                /**
                 * 通过构造器来绑定这个服务(bind),来监听端口
                 * ip:来定位网卡,因为一个机器中会有多个网卡,也会有多个ip
                 * port:定位应用程序
                 */
                serverSocket = new ServerSocket(8080);
    
                //阻塞服务端
                Socket socket = serverSocket.accept();
    
                in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                System.out.println(in.readLine());
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (serverSocket != null) {
                    serverSocket.close();
                }
            }
        }
    

    基于 TCP 实现双向通信对话功能

    客户端

        public static void main(String[] args) {
            try {
                //找到目标的ip和端口
                Socket socket=new Socket("localhost",8080);
    
                //在当前链接上写入输入
                PrintWriter out=new PrintWriter(socket.getOutputStream(),true);
                //控制台的输入流
                BufferedReader sin=new BufferedReader(new InputStreamReader(System.in));
                //拿到输入流
                BufferedReader in=new BufferedReader(new InputStreamReader
                        (socket.getInputStream()));
    
                String readline=sin.readLine(); //获得控制台的输入
                while(!readline.equals("bye")){
                    out.println(readline);
    
                    System.out.println("Server:"+in.readLine());
                    readline=sin.readLine(); //重新获取
                }
    
    
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    

    服务端

        public static void main(String[] args) {
            ServerSocket serverSocket=null;
    
            try {
                //服务端一定需要去监听一个端口号,ip默认就是本机的ip地址
                serverSocket=new ServerSocket(8080);
    
                Socket socket = serverSocket.accept();
    
                //拿到输入流(阻塞, read/write阻塞)
                BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    
                //输出流
                PrintWriter printWriter=new PrintWriter(socket.getOutputStream());
                //通过控制台拿到数据
                BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
                System.out.println("Client:"+in.readLine()); //获得输入流的信息
                String line=sin.readLine(); //获得控制台输入的数据
                while(!line.equals("bye")){
                    printWriter.println(line); //写回到客户端
                    printWriter.flush();
    
                    System.out.println("client:"+in.readLine()); //读取客户端传过来的数据
                    line=sin.readLine(); //重新读取控制台的数据
                }
    
                System.out.println(in.readLine()); //获得客户端的输入信息
    
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    

    socket通信模型

    image.png

    理解TCP的通信原理及IO阻塞

    了解 TCP 协议的通信过程

    image.png

    send():将数据发送到Tcp发送缓冲区
    recv():将数据从Tcp接收缓冲区中读取
    若TCP接收缓冲区满了,则滑动窗口关闭。

    滑动窗口协议

    用于流量控制
    在线演示
    https://media.pearsoncmg.com/aw/ecs_kurose_compnetwork_7/cw/content/interactiveanimations/selective-repeat-protocol/index.html

    发送窗口

    发送端可以不等待应答而连续发送的最大幀数称为发送窗口的尺寸。

    接收窗口

    接收方允许接收的幀的序号表,凡落在接收窗口内的幀,接收方都必须处理,落在接收窗口外的幀被丢弃。

    理解阻塞到底是什么回事

    阻塞指一个服务端只能处理一个客户端的请求,其他客户端的请求阻塞。

    一个客户端对应一个线程

    缺点:线程的个数受限,若线程过多时,增加cpu上下文的切换


    image.png

    非阻塞模型

    阻塞IO

    阻塞IO是当客户端的数据从网卡缓冲区复制到内核缓冲区之前,服务端会一直阻塞。以socket接口为例,进程空间中调用 recvfrom,进程从调用 recvfrom 开始到它返回的整段时间内都是被阻塞的,因此被成为阻塞 IO 模型


    image.png
    非阻塞 IO

    非阻塞 IO 模型的原理很简单,就是进程空间调用 recvfrom,如果这个时候内核缓冲区没有数据的话,就直接返回一个 EWOULDBLOCK 错误,然后应用程序通过不断轮询来检查这个状态状态,看内核是不是有数据过来。


    image.png
    I/O 复用模型

    I/O 多路复用的本质是通过一种机制(系统内核缓冲 I/O 数据),让单个进程可以监视多个文件描述符,一旦某个描述符就绪(一般是读就绪或写就绪),能够通知程序进行相应的读写操作

    相关文章

      网友评论

          本文标题:远程通信协议原理

          本文链接:https://www.haomeiwen.com/subject/kgwxhhtx.html