Java Advanced 3 - Error-prone knowledge points sorting (to be updated)

Java Advanced 3 - Error-prone knowledge points sorting (to be updated)

This chapter is the continuation of Java Advanced 2- Error-prone Knowledge Points ; in the previous chapter, the framework and middleware -related interview questions were
introduced , and in this chapter, it mainly records questions about project deployment middleware and network performance optimization Common interview questions.ORM

15、Docker

Refer to the common commands of Docker (take Anaconda as an example to build the environment) ,

16. Netty (core: channelPipelinedoubly linked list (responsibility chain), used by each node of the linked list promise( wait/notifyevent listener))

Refer to Dark Horse Netty Notes , Shang Silicon Valley Netty Notes , [Hard Core] Live Netty Knowledge Points for a Month , [Reading Notes] Java Game Server Architecture Actual Combat , Code Reference: kebukeYi / book-code

  • [Q] What is the difference between synchronous and asynchronous? What is the difference between blocking and non-blocking IO? (Blocking emphasizes state, while synchronization emphasizes process)

    Note

    • Basic concept :

      • Blocking : Wait for the data in the buffer to be ready before processing other things, otherwise wait there all the time.

      • Non-blocking : When our process accesses our data buffer, if the data is not ready, it will return directly without waiting . If the data is ready, return directly.

      • Synchronization : When a process/thread is executing a certain request , if the request takes a while to return information , then the process/thread will wait until the return information is received before continuing to execute.

      • Asynchronous : The process does not need to wait for the processing result of a certain request , but continues to perform the following operations. When the request is processed, the process can be notified to process through the callback function .

      Blocking and synchronous (non-blocking and asynchronous) descriptions are the same, but the emphasis is different: blocking emphasizes state, while synchronization emphasizes process .

    • Blocking IO and non-blocking IO: ( BIO vs NIO )

      • BIO(Blocking IO):

        • The traditional java.io package , which is implemented based on the stream model, provides some of the IO functions we are most familiar with, such as File abstraction, input and output streams, and so on. The interactive mode is synchronous and blocking . That is to say, when reading the input stream or writing the output stream, the thread will be blocked there until the reading and writing actions are completed, and the calls between them are in a reliable linear order.

        • In Javanetwork communication, Socketsockets and ServerSocketsockets are implemented based on blocking mode.

          insert image description here

      • NIO(Non-Blocking IO):

        • Java 1.4The corresponding java.niopackage , providing abstractions such as Channel, Selector, Bufferetc., which support buffer-oriented, channel-based I/O operation methods.

        • NIO Socketprovides two different socket channel implementations ServerSocketcorresponding SocketChannelto and in the traditional BIO model, supporting both blocking and non-blocking modes . For high-load, high-concurrency (network) applications, NIO's non-blocking mode should be used for development.ServerSocketChannel

          insert image description here

      • BIOCompare with NIO:

        IO model BIO NIO
        communication flow-oriented buffer -oriented
        deal with blocking IO non-blocking IO
        trigger none Selector
  • [Q] What is CPU-intensive/IO-intensive? (There are multiple types of tasks, you need to consider using multiple thread pools)

    Note

    • The management of the number of threads in the game business processing framework needs to consider the type of task: I/O-intensive, computing-intensive, or both; if there are multiple types of tasks, you need to consider using multiple thread pools :

      • Business processing is computationally intensive (such as the calculation of total combat power in the game, battle report inspection, and business logic processing. If there are N processors, it is recommended to allocate N+1 threads)

      • Database operations are IO-intensive , such as database and Redis read and write, network I/O operations (communication between different processes), disk I/O operations (log file writing), etc.

      Allocating two independent thread pools can make business processing unaffected by database operations

    • In the use of threads, it is necessary to use the corresponding thread pool strictly according to different task types . In game service development, it is strictly regulated that developers cannot create new threads at will. If there are special circumstances, special instructions are required, and the evaluation of its usability should be done to prevent too many places from creating threads, which will eventually become uncontrollable .

  • [Q] What is Netty? Why learn Netty? (asynchronous, event-driven network framework)

    Note

    • Netty is an asynchronous, event-driven network application framework , which java.niois encapsulated on the basis (the client SocketChannelis encapsulated NioSocketChannel, and the server is ServerSocketChannelencapsulated NioServerSocketChannel), which is used to quickly develop maintainable and high-performance network servers and clients . NettyThe status of a Javaweb application framework is like the status of Springa framework in JavaEEdevelopment .

    • In order to ensure the needs of network communication, the following frameworks use Netty:

      • Cassandra- nosql database
      • Spark- Big data distributed computing framework
      • Hadoop- Big data distributed storage framework
      • RocketMQ- ali open source message queue
      • ElasticSearch- search engine
      • gRPC- rpc framework
      • Dubbo- rpc framework
      • Spring 5.x- The flux api completely abandons tomcat and uses netty as the server side
      • Zookeeper- Distributed coordination framework
  • [Q] What are the core components of Netty? (thread pool + selector + channel (the bottom layer is file cache) + task queue + channelPipeline (responsibility chain, including multiple handlers to handle different events)), refer to how Netty encapsulates Socket client Channel, what are the types of Netty Channel? , Netty's core components , netty execution process and detailed explanation of core modules (must-see series for beginners)

    Note

    • Basic concepts of core components :

      • Event loop group (EventLoopGroup) : The event loop group can be simply understood as a thread pool , which contains multiple event loop threads (that is EventLoop), when initializing the event loop group, you can specify the number of event loops to create .

      • Each event loop thread is bound to a task queue , which is used to process non-IO events, such as channel registration, port binding,EventLoop etc. All threads in the event loop group are active , and each EventLoopthread is bound to a selector ( Selector), a selector ( Selector) registers multiple channels (client connections), when the channel generates an event , the event loop thread bound to the selector will activate and process the event .

      • For BossGroupthe event loop group, the event loop inside only listens to the connection event of the channel (ie accept().

      • For WorkerGroupthe event loop group, the event loop inside only listens to the read event ( read()) . If the connection event ( accept()) of the channel is monitored, it will be handed over to BossGroupan event loop in the event loop group for processing . After processing, the client channel (channel) will be generated and registered to an event loop in the WorkerGroup event loop group, and bound to read Event, this event loop will monitor the read event, when the client initiates a read and write request, this event loop will monitor and process it .

        • Selector (selector) : Selectorbind an event loop thread ( EventLoop), on which multiple channels can be registered (which can be simply understood as client connection ), Selectorresponsible for monitoring channel events (connection, read and write) , when the client initiates a read When writing a request, Selectorthe bound event thread ( EventLoop) will wake up and read events from the channel for processing.

        • Task queue and tail task queue : An event loop binds a task queue and tail queue for storing channel events.

        • Channel (channel) : When a Linux program performs any form of IO operations, it is manipulating files (for example, you can sed|awkview the process status through commands, and the content of the process is actually a file). Since the TCP/IP protocol stack is supported in the UNIX system, it is equivalent to introducing a new IO operation, that is, Socket IO, which is dedicated to network transmission. Therefore, the Linux system regards Socket as a kind of file .

          When we use Socket IO to send data, we are actually manipulating files:

          • First open the file, write the data into the file (the upper layer of the file also has a layer of cache, called file cache ), and then copy the data in the file cache to the sending buffer of the network card ;

          • Then send the data in the buffer to the receiving buffer of the other party's network card through the network card. After the other party's network card receives the data , it opens the file, copies the data to the file, and then copies the data in the file cache to the user cache , and then processes data.

          ChannelIt is Socketthe right package, so its bottom layer is also operating files , so Channelwhat is operating is operating Socket, and the operation Socket(itself a kind of file) is operating files.

          NettyRe-encapsulate the client SocketChanneland serverServerSocketChannel in the JDK respectively to obtain NioSocketChanneland NioServerSocketChannel.

      • Pipeline (ChannelPipeline) : The pipeline is a linked list with a group of encoders as nodes, which is used to process client requests, and it is also the place where business logic is actually processed .

      • Processor (ChannelHandler) : A processor is a node of the pipeline, and a client request is usually processed one by one by all handlers in the pipeline.

      • Event KEY (selectionKey) : When the channel ( channel) generates an event , Selectorit will generate an selectionKeyevent and wake up the event thread to process the event .

      • Buffer : NIO is a block-oriented IO. After reading data from the channel, it will be put into the buffer (Buffer). When writing data to the channel, it needs to be written into the buffer first. In short, it is impossible to read data directly from the channel. , and cannot directly write data to the channel.

      • Buffer Pool (BufferPool) : This is Nettyan optimization method for memory, which manages fixed-size memory through a pooling technology . (When a thread needs to store data, it can directly obtain the memory from the buffer pool , and put it back when it is not needed, so that there is no need to re-apply for memory frequently, because applying for memory takes time and affects performance)

      • ServerBootstrap and Bootstrap : Bootstrapand ServerBootstrapare called the bootstrap class, which refers to the process of configuring the application and making it run. NettyBootstrapping is handled by isolating your application from the network layer.

        • BootstrapIt is the bootstrap class of the client . When the (connect UDP) and (connect TCP) methods Bootstrapare called , a new one will be created , and only a single one without a parent Channel will be created to realize all network exchanges.bind()connect()ChannelChannel

        • ServerBootstrapIt is the bootstrap class of the server . ServerBootstrapWhen bind()the method , a will be created ServerChannelto accept the connection from the client , and the ServerChannel manages multiple sub-Channels for communication with the client .

      • ChannelFuture : ​All I/O operations in
        Netty , that is, the operation will not return results immediately, so an object as the "spokesman" of this asynchronous operation, representing the asynchronous operation itself. If you want to get the return value of the asynchronous operation, you can add the NIO network programming framework Netty listener to the asynchronous operation through the method of the asynchronous operation object, and register a callback for it: call and execute immediately after the result comes out .ChannelFutureaddListener()

        NettyThe asynchronous programming model is built Futureon call_back()top of the callback concept.

    • The relationship between components and components is as follows:

      • An event loop group ( EventLoopGroup) contains multiple event loops ( EventLoop) - 1 ... *;
      • A selector ( selector) can only be registered into one event loop ( EventLoop) - 1 ... 1;
      • An event loop ( EventLoop) contains a task queue and a tail task queue - 1 ... 1;
      • A channel ( channel) can only be registered in one selector ( selector) - 1 ... 1;
      • A channel ( channel) can only be bound to one pipe ( channelPipeline) - 1 ... 1;
      • A pipeline ( channelPipeline) contains multiple service orchestration processors ( channelHandler)
      • Netty channel ( NioSocketChannel/NioServerSocketChannel) and native NIO channel ( SocketChannel/SocketServerChannel) correspond one-to-one and bind - 1 ... 1;
      • A channel can focus on multiple IO events;
  • [Q] What is the execution process of Netty? (Top-down analysis/client-server analysis) , refer to an article to understand the overall process of Netty , netty execution process and detailed explanation of core modules (must-see series for beginners)

    Note

    • Top-down analysis process : NioEventLoopGroup -> NioEventLoop -> selector -> channel, NioEventLoop listens to different channels (NioEventLoop in BossGroup listens to accept, NioEventLoop in work Group listens to read/write events)

      insert image description here

      • Netty abstracts two sets of thread pools, BossGroupwhich are responsible for receiving connections from clients and WorkerGroupreading and writing the network ;

        BossGroupand are WorkerGroupof typeNioEventLoopGroup

      • NioEventLoopGroupEquivalent to an event loop group , this group contains multiple event loops, each event loop is NioEventLoop;

        • NioEventLoopRepresents a thread that executes processing tasks in a continuous cycle ( selectormonitoring whether the binding event occurs), each NioEventLoophas one Selector, used to monitor the network communication socketof the , such as NioServerSocketChannelbound to the server , bound to On the client side , and then each of them will continuously monitor related events in a loop .bossgroupNioEventLoopselectorNioSocketChannelNioEventLoopselectorselector

        • NioEventLoopGroupThere can be multiple threads, that is, there can be multipleNioEventLoop

      • Each of BossGroupthe following NioEventLooploops executes 3 steps

        1. polling acceptevents

        2. Handles acceptevents , clientestablishes a connection with , generates NioScocketChannel, and registers it with workerGroup NIOEventLoopaSelector

        3. Continue to process the tasks of the task queue , i.e.runAllTasks

      • Each of WorkerGroupthe following NIOEventLooploops executes the steps

        1. polling read, writeevent

        2. Handling I/Othe event , that is, read,writethe event, NioScocketChannelis processed .

        3. Process the tasks of the task queue , i.e.runAllTasks

      • Each of Workerthe following NIOEventLoopwill use pipeline(pipeline) when processing business, pipelinewhich contains channel(channel), that is, the corresponding channel pipelinecan obtained through , and many processors are maintained in the pipeline .

      • NioEventLoopThe serial design is adopted internally , from message reading -> decoding -> processing -> encoding -> sending , the IO thread is always NioEventLoopresponsible

      • NioEventLoopGroupNioEventLoop
        Each contains NioEventLoopone Selector, and taskQueue
        each can register to listen to multiple, and each can only be bound toNioEventLoop a unique one . Each is bound to have its own. You can get the corresponding one , and you can also get the corresponding one. .SelectorNioChannel
        NioChannelNioEventLoop
        NioChannelChannelPipeline
        NioChannelChannelPipelineChannelPipelineNioChannel

    • The client-server analysis process is as follows:

      1. ServerStart, select one Nettyfrom ParentGroup( ) to monitor the specified .BossGroupNioEventLoopport

      2. ClientStart, select a connection Nettyfrom ParentGroup( BossGroup) .NioEventLoopServer

      3. Clientconnected , createdServer _portChannel

      4. NettySelect a binding from ( ) to handle ChildGroupall operations in it .WorkGroupNioEventLoopchannelChannel

      5. ClientBy sending packets Channelto .Server

      6. PipelineThe processor in the process uses the chain of responsibility mode to Channelprocess the data packets in the

      7. Server needs to send data to Client . Then the data needs to be processed by the processorpipeline in the computer and processed into data packets for transmission .
        ByteBuf

      8. ServerchannelSend the packet viaClient

      9. PipelineThe processor in the process uses the chain of responsibility mode to channelprocess the data packets in the

      insert image description here

  • [Q] How to use Netty to easily realize the communication between multiple clients and servers?

    Note

    • Referring to the Netty execution process of the client/server in the previous question , the following code is given

      • Server:

        package org.example.code001_helloworld;
        import io.netty.bootstrap.ServerBootstrap;
        import io.netty.channel.Channel;
        import io.netty.channel.ChannelHandlerContext;
        import io.netty.channel.ChannelInitializer;
        import io.netty.channel.SimpleChannelInboundHandler;
        import io.netty.channel.nio.NioEventLoopGroup;
        import io.netty.channel.socket.nio.NioServerSocketChannel;
        import io.netty.channel.socket.nio.NioSocketChannel;
        import io.netty.handler.codec.string.StringDecoder;
        
        public class HelloServer {
                  
                  
        
            public static void main(String[] args) throws InterruptedException{
                  
                  
                //通过ServerBootStrap引导类创建channel
                ServerBootstrap sb = new ServerBootstrap()
                                    .group(new NioEventLoopGroup())  //2、选择事件循环组为NioEventLoopGroup,返回ServerBootstrap
                                    .channel(NioServerSocketChannel.class) //3、选择通道实现类为NioServerSocketChannel,返回ServerBootstrap
                                    .childHandler(  //为channel添加处理器,返回返回ServerBootstrap
                                            new ChannelInitializer<NioSocketChannel>(){
                  
                  
                                                //4、初始化处理器,用来监听客户端创建的SocketChannel
                                                protected void initChannel(NioSocketChannel ch) throws Exception {
                  
                  
                                                    ch.pipeline().addLast(new StringDecoder()); // 5、处理器1用于将ByteBuf解码为String
                                                    ch.pipeline().addLast(new SimpleChannelInboundHandler<String>() {
                  
                   // 6、处理器2即业务处理器,用于处理上一个处理器的处理结果
                                                        @Override
                                                        protected void channelRead0(ChannelHandlerContext ctx, String msg) {
                  
                  
                                                            System.out.println(msg);  //输出客户端往NioSocketChannel中发送端数据
                                                        }
                                                    });
                                                }
                                            }
                                    );
                                    );
                // sb.bind("127.0.0.1",8080);  //监听客户端的socket端口
        		ChannelFuture channelFuture = sb.bind("127.0.0.1",8080);  //监听客户端的socket端口(默认127.0.0.1)
                //设置监听器
                channelFuture.addListener(new GenericFutureListener<Future<? super Void>>() {
                  
                  
                     @Override
                     public void operationComplete(Future<? super Void> future) throws Exception {
                  
                  
                        if(future.isSuccess()){
                  
                  
                            System.out.println("端口绑定成功");
                        }else{
                  
                  
                            System.out.println("端口绑定失败");
                        }
                     }
                });
        
                while(true){
                  
                  
                    Thread.sleep(1000);  //睡眠5s
                    System.out.println("我干我的事情");
                }
            }
        }
        
      • client:

        package org.example.code001_helloworld;
        import io.netty.bootstrap.Bootstrap;
        import io.netty.channel.Channel;
        import io.netty.channel.ChannelInitializer;
        import io.netty.channel.nio.NioEventLoopGroup;
        import io.netty.channel.socket.nio.NioSocketChannel;
        import io.netty.handler.codec.string.StringEncoder;
        
        import java.util.Date;
        
        public class HelloClient{
                  
                  
        
            public static void main(String[] args) throws InterruptedException {
                  
                  
        
                int i = 3;
                while(i > 0) {
                  
                  
                    Channel channel = new Bootstrap()   //客户端启动类,用于引导创建channel;其中Bootstrap继承于AbstractBootstrap<Bootstrap, Channel>,即一个map集合
                            .group(new NioEventLoopGroup()) // 1、选择事件循环组类为NioEventLoopGroup,返回Bootstrap
                            .channel(NioSocketChannel.class) // 2、选择socket实现类为NioSocketChannel,返回Bootstrap
                            .handler(new ChannelInitializer<Channel>() {
                  
                   // 3、添加处理器,返回Bootstrap:创建ChannelInitializer抽象类的匿名内部类,重写initChannel,处理器是Channel的集合
                                @Override //在连接建立后被调用
                                protected void initChannel(Channel ch) {
                  
                  
                                    ch.pipeline().addLast(new StringEncoder());
                                }
                            })
                            .connect("127.0.0.1", 8080) // 4、与server建立连接,返回ChannelFuture
                            .sync() // 5、同步阻塞,等待连接建立,返回ChannelFuture
                            .channel(); // 6、成功创建通道,返回Channel,通道即为socket文件
        
                    channel.writeAndFlush(new Date() + ": hello world! My name is wang" + i);  //7、向channel中写入数据,发送给server
                    i--;
                }
            }
        }
        
      • Start the server first, and then open the three clients; the server listens to the data sent by the client from port 8080 through a custom processor, and prints it to the console .

        我干我的事情
        我干我的事情
        我干我的事情
        我干我的事情
        Thu Nov 10 23:17:03 CST 2022: hello world! My name is wang1
        Thu Nov 10 23:17:03 CST 2022: hello world! My name is wang3
        Thu Nov 10 23:17:03 CST 2022: hello world! My name is wang2
        我干我的事情
        我干我的事情
        我干我的事情
        我干我的事情
        
    • A simple analysis of the above code flow:

      • The server first selects a thread from the thread pool to listen to the server-bound ipand port (ie 127.0.0.1and 8080).

        The port here is the only entrance for the client to access the server . When multiple clients send a large number of requests to the server at the same time, if the server receives each client's request one by one, there will be a blocking waiting problem .

      • In order to solve the blocking problem, different requests from the client are stored in the port monitored by the server in the form of files through differentchannel files (ie, file cache) , so here the server opens a thread to listen to this port, and the thread is bound selectorto allow selectorcompletion Event handling works.

      • After channelthe transfer is complete (the file cache is full and written to the file), the data will be processed selectorthrough channelPipelinethe user-defined one .channelHandler

  • [Q] What is the difference between juc.Future, callback function, and netty promise? (Promise combines the advantages of Future and callback functions to achieve asynchrony; the Promise interface uses the observer mode, that is, the addListenerlistener is set through, the listener is promise.awaitblocked, and the processing thread promise.notifywakes up the listener)

    Note

    Here juc.Future, Consumerthe functional interface and netty promiseare used respectively to simulate the database data query process :

    • While waiting for juc.Futurethe return result, the main thread is blocked .

      package org.example.code000_JUC_test;
      
      import java.util.concurrent.Callable;
      import java.util.concurrent.CancellationException;
      import java.util.concurrent.FutureTask;
      
      public class code001_future_test {
              
              
      
          //模拟数据库查询操作
          public String getUsernameById(Integer id) throws InterruptedException{
              
              
              Thread.sleep(1000);  //模拟IO过程
              return "wangxiaoxi";
          }
      
          public static void main(String[] args) {
              
              
      
              final code001_future_test obj = new code001_future_test();
      
              //FutureTask处理的数据类型即为Callable异步返回的数据类型
              FutureTask<String> futureTask = new FutureTask<String>(new Callable<String>(){
              
              
                  public String call() throws Exception {
              
              
                      System.out.println("thread1正在异步执行中");
                      String username = obj.getUsernameById(1);
                      System.out.println("callable over");
                      return username;
                  }
              });
              //创建线程并异步执行
              Thread thread = new Thread(futureTask);
              thread.start();
      
              try{
              
              
                  System.out.println("mainThread开始操作");
                  String res = futureTask.get();   //主线程会阻塞,同步等待线程1执行结束,并返回值
                  System.out.println("thread1处理完毕," + "用户名为:" + res);
      
                  int i = 5;
                  while(i > 0){
              
              
                      System.out.println("mainThread正在执行中");
                      Thread.sleep(1000);
                      i--;
                  }            
                  System.out.println("mainThread结束操作");
              }catch (InterruptedException e){
              
              
                  e.printStackTrace();
              }catch (Exception e){
              
              
                  e.printStackTrace();
              }
          }
      }
      ---
      mainThread开始操作
      thread1正在异步执行中
      callable over
      thread1处理完毕,用户名为:wangxiaoxi
      mainThread正在执行中
      mainThread正在执行中
      mainThread正在执行中
      mainThread正在执行中
      mainThread正在执行中
      mainThread结束操作
      
    • The return result is processed through the callback function ( Consumer<String> consumer+ lambda8expression), and the main thread can still complete other operations at this time without blocking and waiting for the return result of other threads. But there will be a concurrency problemconsumer of being used by multiple threads at the same time .

      package org.example.code000_JUC_test;
      import java.util.function.Consumer;
      
      public class code002_consumer_test {
              
              
      
         //模拟数据库查询操作, 其中consumer是回调函数, 所以该函数无返回值
          public void getUsernameById(Integer id, Consumer<String> consumer) throws InterruptedException{
              
              
              Thread.sleep(1000);  //模拟IO过程
              String username =  "wangxiaoxi";
              consumer.accept(username);
          }
      
          public static void main(String[] args) throws InterruptedException{
              
              
      
              final code002_consumer_test obj = new code002_consumer_test();
              Consumer<String> consumer = ((s) -> {
              
               System.out.println("thread1处理完毕,用户名为:" + s); });  //通过回调函数异步执行
      
              Thread thread = new Thread(new Runnable(){
              
              
                  public void run() {
              
              
                      try {
              
              
                          System.out.println("thread1正在异步执行中");
                          obj.getUsernameById(1,consumer);  //函数式编程: consumer有入参,无返回值
                      } catch (InterruptedException e) {
              
              
                          throw new RuntimeException(e);
                      }
                  }
              });
              thread.start();
      
              System.out.println("mainThread开始操作");
              int i = 5;
              while(i > 0){
              
              
                  System.out.println("mainThread正在执行中");
                  Thread.sleep(1000);
                  i--;
              }
              System.out.println("mainThread结束操作");
      
          }
      
      }
      ---
      
      mainThread开始操作
      mainThread正在执行中
      thread1正在异步执行中
      mainThread正在执行中
      thread1处理完毕,用户名为:wangxiaoxi
      mainThread正在执行中
      mainThread正在执行中
      mainThread正在执行中
      mainThread结束操作
      
    • nettyThe interface is rewritten juc.Future, and a sub-interface is derived on this basis promise. You can monitor whether it has been processed by other threads promiseby setting a listener ( at this time , by blocking and waiting for the processing result, when it has been processed by other threads, the thread will wake up by , notify it to process the result ; if it means the processing is successful, if it means the processing failed).promiselistenerpromise.awaitpromisepromisepromise.notifylistenerfuture.isSuccess()future.Cancelled()

      package org.example.code000_JUC_test;
      import io.netty.util.concurrent.DefaultEventExecutor;
      import io.netty.util.concurrent.DefaultEventExecutorGroup;
      import io.netty.util.concurrent.DefaultPromise;
      import io.netty.util.concurrent.EventExecutor;
      import io.netty.util.concurrent.EventExecutorGroup;
      import io.netty.util.concurrent.Future;
      import io.netty.util.concurrent.GenericFutureListener;
      import io.netty.util.concurrent.Promise;
      
      import java.util.function.Consumer;
      
      public class code003_netty_test {
              
              
      
          public Future<String> getUsernameById(Integer id,Promise<String> promise) throws InterruptedException{
              
              
      
              //模拟从数据库线程池中取出某一个线程进行操作
              new Thread(new Runnable() {
              
              
                  @Override
                  public void run() {
              
              
                      System.out.println("thread2正在异步执行中");
                      try {
              
              
                          Thread.sleep(1000);  //模拟IO过程
                      } catch (InterruptedException e) {
              
              
                          throw new RuntimeException(e);
                      }
                      String username =  "wangxiaoxi";
                      System.out.println("thread2处理完毕");
                      promise.setSuccess(username);
                  }
              }).start();
              return promise;   //返回promise的线程和处理promise线程并不是同一个线程
          }
      
          public static void main(String[] args) throws InterruptedException{
              
              
      
              code003_netty_test obj = new code003_netty_test();
              EventExecutor executor = new DefaultEventExecutor();  //通过netty创建线程
              executor.execute(new Runnable() {
              
              
                  @Override
                  public void run() {
              
              
                      System.out.println("thread1正在异步执行中");
                      //异步调用返回值(继承于netty.Future,可用于设置监听器)
                      Promise<String> promise = new DefaultPromise<String>(executor);
                      //设置监听器,阻塞等待(object.await)直到promise返回结果并对其进行处理
                      try {
              
              
                          obj.getUsernameById(1,promise).addListener(new GenericFutureListener<Future<? super String>>() {
              
              
                              @Override
                              public void operationComplete(Future<? super String> future) throws Exception {
              
              
                                  System.out.println("thread1.listener监听完毕");
                                  if(future.isSuccess()){
              
              
                                      System.out.println("thread1.listener监听到promise的返回值");
                                      String username = (String)future.get();
                                      System.out.println("thread1处理完毕,用户名为:" + username);
                                  }
                              }
                          });
                      } catch (InterruptedException e) {
              
              
                          throw new RuntimeException(e);
                      }
                  }
              });
      
              System.out.println("mainThread开始操作");
              int i = 5;
              while(i > 0){
              
              
                  System.out.println("mainThread正在执行中");
                  Thread.sleep(1000);
                  i--;
              }
              System.out.println("mainThread结束操作");
          }
      }
      ---
      mainThread开始操作
      mainThread正在执行中
      thread1正在异步执行中
      thread2正在异步执行中
      mainThread正在执行中
      thread2处理完毕
      thread1.listener监听完毕
      thread1.listener监听到promise的返回值
      thread1处理完毕,用户名为:wangxiaoxi
      mainThread正在执行中
      mainThread正在执行中
      mainThread正在执行中
      mainThread结束操作
      

      promiseCombining Futurethe advantages of the callback function and the callback function , the creation and processing of the callback function may not be in the same thread (thread 1 is created promise, and the child thread 2 of thread 1 is used for processing promise, so there is no concurrency problem)

  • [Q] What can ChannelFuture and Promise be used for? What is the difference between the two? ( ChannelFutureSame Promiseas both, inherited from netty Future, can be used to return asynchronous processing results) , refer to Netty asynchronous callback mode - Future and Promise analysis

    Note

    • NettyInherited Futurefrom JDK Future, through the Object wait/notifymechanism , the synchronization between threads is realized ; using the observer design pattern , asynchronous non-blocking callback processing is realized . in:

      • ChannelFutureand Promiseboth are Nettysubinterfaces Future;

      • ChannelFutureand Channelbinding for asynchronous processing Channelof events ; but Futurethe return value cannot be set according to the execution status of

      • PromiseOn the basis of Netty , Futurefurther encapsulation is carried out , and the function of setting return value and exception message is added , and the return result is customizedFuture according to the return result of different data processing , such as:

        @Override
        public void channelRegister(AbstractGameChannelHandlerContext ctx, long playerId, GameChannelPromise promise) {
                  
                  
        
            // 在用户GameChannel注册的时候,对用户的数据进行初始化
            playerDao.findPlayer(playerId, new DefaultPromise<>(ctx.executor())).addListener(new GenericFutureListener<Future<Optional<Player>>>() {
                  
                  
                @Override
                public void operationComplete(Future<Optional<Player>> future) throws Exception {
                  
                  
                    Optional<Player> playerOp = future.get();
                    if (playerOp.isPresent()) {
                  
                  
                        player = playerOp.get();
                        playerManager = new PlayerManager(player);
                        promise.setSuccess();
                        fixTimerFlushPlayer(ctx);// 启动定时持久化数据到数据库
                    } else {
                  
                  
                        logger.error("player {} 不存在", playerId);
                        promise.setFailure(new IllegalArgumentException("找不到Player数据,playerId:" + playerId));
                    }
                }
            });
        }
        

        When the message is set successfully, listenerthe processing result will be notified immediately; once setSuccess(V result)or setFailure(V result), those await()or sync()threads will return from waiting.

      • ChannelPromiseinherits ChannelFutureand Promiseis a writable ChannelFutureinterface

    • ChannelFutureInterface: NettyAll I/Ooperations are asynchronous, for example bind, connect, writeand other operations will return an ChannelFutureinterface. The asynchronous callback processing mode is widely used in the Netty source code . For example, when the interface is bound to a task, the callback of the asynchronous processing result can be realized by setting the Listener . This process is called passive callback .

      ...
       ChannelFuture channelFuture = sb.bind("127.0.0.1",8080);  //监听客户端的socket端口
       //设置监听器
       channelFuture.addListener(new GenericFutureListener<Future<? super Void>>() {
              
              
           @Override
           public void operationComplete(Future<? super Void> future) throws Exception {
              
              
               if(future.isSuccess()){
              
              
                   System.out.println("端口绑定成功");
               }else{
              
              
                   System.out.println("端口绑定失败");
               }
           }
       });
      ...
      

      ChannelFuturechannelIt is associated with the channel in the IO operation and is used to process channel events asynchronously . This interface is used most in practice. ChannelFutureCompared with the parent class interface Future, the interface adds channel()and isVoid()two methods

      ChannelFutureThe methods defined by the interface are as follows:

      public interface ChannelFuture extends Future<Void> {
              
              
          // 获取channel通道
          Channel channel();
          @Override
          ChannelFuture addListener(GenericFutureListener<? extends Future<? super Void>> listener);
          @Override
          ChannelFuture addListeners(GenericFutureListener<? extends Future<? super Void>>... listeners);
          @Override
          ChannelFuture removeListener(GenericFutureListener<? extends Future<? super Void>> listener);
          @Override
          ChannelFuture removeListeners(GenericFutureListener<? extends Future<? super Void>>... listeners);
          @Override
          ChannelFuture sync() throws InterruptedException;
          @Override
          ChannelFuture syncUninterruptibly();
          @Override
          ChannelFuture await() throws InterruptedException;
          @Override
          ChannelFuture awaitUninterruptibly();
          // 标记Futrue是否为Void,如果ChannelFuture是一个void的Future,不允许调// 用addListener(),await(),sync()相关方法
          boolean isVoid();
      }
      

      ChannelFutureThere are two states Uncompleted (unfinished) and Completed (completed) , Completedincluding three types, execution success, execution failure and task cancellation . Note: Both execution failure and task cancellation belong to Completed .

    • PromiseInterface: PromiseIt is writable ,Future and the interface definition is as follows

      public interface Promise<V> extends Future<V> {
              
              
          // 执行成功,设置返回值,并通知所有listener,如果已经设置,则会抛出异常
          Promise<V> setSuccess(V result);
          // 设置返回值,如果已经设置,返回false
          boolean trySuccess(V result);
          // 执行失败,设置异常,并通知所有listener
          Promise<V> setFailure(Throwable cause);
          boolean tryFailure(Throwable cause);
          // 标记Future不可取消
          boolean setUncancellable();
      
          @Override
          Promise<V> addListener(GenericFutureListener<? extends Future<? super V>> listener);
          @Override
          Promise<V> addListeners(GenericFutureListener<? extends Future<? super V>>... listeners);
          @Override
          Promise<V> removeListener(GenericFutureListener<? extends Future<? super V>> listener);
          @Override
          Promise<V> removeListeners(GenericFutureListener<? extends Future<? super V>>... listeners);
          @Override
          Promise<V> await() throws InterruptedException;
          @Override
          Promise<V> awaitUninterruptibly();
          @Override
          Promise<V> sync() throws InterruptedException;
          @Override
          Promise<V> syncUninterruptibly();
      }
      
      • FutureThe interface only provides get()methods to get the return value , and the return value cannot be set .

      • PromiseBased on the interface Future, it also provides setting return value and exception information, and immediately notifies listeners . Moreover, once setSuccess(...) or setFailure(...)after, those await()or sync()threads will return from waiting.

        There are two ways of synchronous blocking: sync() and await() , the difference: sync()the method will ; await()the method does not do any processing on the exception information , which can be used when we don't care about the exception information await().

        By reading the source code, we can see that sync()the method is actually adjusted in await()the method.

        // DefaultPromise 类
        
         @Override
        public Promise<V> sync() throws InterruptedException {
                   
                   
            await();
            rethrowIfFailed();
            return this;
        }
        
    • By inheriting Promisethe interface, get about ChannelFuturethe writable sub-interface ChannelPromise;

      PromiseThe implementation class is to implement thread synchronization DefaultPromisethrough Object , and to ensure the visibility between threads through keywords.wait/notifyvolatile

      ChannelPromiseThe implementation class is DefaultChannelPromise, and its inheritance relationship is as follows:

  • [Ask] The execution process of ChannelPipeline (ChannelHandler is encapsulated into ChannelHandlerContext in ChannelPipeline, and read and write processing is realized through tail and head identification) , refer to Netty's TCP sticky packet and unpacking solution , Dark Horse Netty Tutorial

    Note

    • SelectorAfter polling the network IO event , it will call the Channelcorresponding one ChannelPipelineto execute the corresponding ones in turnChannelHandler . The event-driven Nettyframework is as follows:

    • We already ChannelPipelineknow ChannelHandlerthe relationship between and above : ChannelPipelineit is a ChannelHandlercontainer for storing various pipes. ChannelPipelineThe execution flow is as follows ( it is ChannelHandleralso divided into two categories: ChannelInboundHandlerit is used to handle link read events Handler, ChannelOutboundHandlerand it is used to handle link write events Handler):

      1. NioEventLoop When a read event is triggered , SocketChannelthe associatedChannelPipline
      2. The messages read in the previous step will ChannelPiplinebe processed by multiple in turn ChannelInboundHandler.
      3. ChannelHandlerContextAfter the message is processed write, the method will be called to send the message. At this time , the write event is triggered , and the sent message will also go through ChannelPiplinemultiple processes in ChannelOutboundHandlerthe process.
    • One channelis bound to onechannelPipeline , and can be added by channelobtaining ; the initialization code is as follows:channelPipelinechannelHandlerchannelPipeline

      eventGroup = new NioEventLoopGroup(gameClientConfig.getWorkThreads());// 从配置中获取处理业务的线程数
              bootStrap = new Bootstrap();
              bootStrap.group(eventGroup).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true).option(ChannelOption.SO_KEEPALIVE, true).option(ChannelOption.CONNECT_TIMEOUT_MILLIS, gameClientConfig.getConnectTimeout() * 1000).handler(new ChannelInitializer<Channel>() {
              
              
                  @Override
                  protected void initChannel(Channel ch) throws Exception {
              
              
                      ch.pipeline().addLast("EncodeHandler", new EncodeHandler(gameClientConfig));// 添加编码
                      ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(1024 * 1024 * 4, 0, 4, -4, 0));// 添加解码
                      ch.pipeline().addLast("DecodeHandler", new DecodeHandler());// 添加解码
                      ch.pipeline().addLast("responseHandler", new ResponseHandler(gameMessageService));//将响应消息转化为对应的响应对象
                     // ch.pipeline().addLast(new TestGameMessageHandler());//测试handler
                      ch.pipeline().addLast(new IdleStateHandler(150, 60, 200));//如果6秒之内没有消息写出,发送写出空闲事件,触发心跳
                      ch.pipeline().addLast("HeartbeatHandler",new HeartbeatHandler());//心跳Handler
                      ch.pipeline().addLast(new DispatchGameMessageHandler(dispatchGameMessageService));// 添加逻辑处理
      
                  }
              });
              ChannelFuture future = bootStrap.connect(gameClientConfig.getDefaultGameGatewayHost(), gameClientConfig.getDefaultGameGatewayPort());
              channel = future.channel();
      
    • ChannelHandlerChannelPiplineStructure in :

      ChannelHandlerBefore joining ChannelPipline, it will be encapsulated into a ChannelHandlerContextnode class and added to a doubly linked list structure. Except for the two special ChannelHandlerContextimplementation classes at the head and the tail , everything we customize ChannelHandlerwill eventually be encapsulated into a DefaultChannelHandlerContextclass.

      • When a read event is triggered, the triggering sequence ChannelHandler(which will filter the type of Handler) is ->ChannelInboundHandlerHeaderContextTailContext

      • When a write event is triggered, the trigger sequence ChannelHandler(which will filter the type of Handler) is opposite to that of the read event ->ChannelOutboundHandlerTailContextHeaderContext

      It can be seen that nio workers and non-nio workers are also bound to channels respectively (LoggingHandler is executed by nio workers, while its own handler is executed by non-nio workers)

  • [Q] What are the events in ChannelPipeline? (An event can be understood as an IO operation, such as database query, network communication, etc.; this function can be called back through the Promise object)

    Note

    • Custom event class - GetPlayerInfoEventas follows , can be used to identify the same type of I/O event operation, for example, the same event ID will be triggered when getPlayerName()and , at this time, the thread listening to the event ID will process the monitored result (as shown in the above figure Processor nodes in different channels can execute with the same event thread ):getPlayerLevel()EventLoop

      public class GetPlayerInfoEvent {
              
              
          private Long playerId;
      
          public GetPlayerInfoEvent(Long playerId) {
              
              
              super();
              this.playerId = playerId;
          }
      
          public Long getPlayerId() {
              
              
              return playerId;
          }
      }
      
    • The core method of sending events to is not based on annotationschannelPipeline is as follows:

      @Override
      public void userEventTriggered(AbstractGameChannelHandlerContext ctx, Object evt, Promise<Object> promise) throws Exception {
              
              
          if (evt instanceof IdleStateEvent) {
              
              
              logger.debug("收到空闲事件:{}", evt.getClass().getName());
              ctx.close();
          }
           else if (evt instanceof GetPlayerInfoEvent) {
              
              
           GetPlayerByIdMsgResponse response = new GetPlayerByIdMsgResponse();
           response.getBodyObj().setPlayerId(this.player.getPlayerId());
           response.getBodyObj().setNickName(this.player.getNickName());
           Map<String, String> heros = new HashMap<>();
           this.player.getHeros().forEach((k,v)->{
              
              //复制处理一下,防止对象安全溢出。
           heros.put(k, v);
           });
           //response.getBodyObj().setHeros(this.player.getHeros());不要使用这种方式,它会把这个map传递到其它线程
           response.getBodyObj().setHeros(heros);
           promise.setSuccess(response);
           }
           
          UserEventContext<PlayerManager> utx = new UserEventContext<>(playerManager, ctx);
          dispatchUserEventService.callMethod(utx, evt, promise);
      }
      

      in:

      • UserEventContextis for AbstractGameChannelHandlerContextfurther encapsulation
      • AbstractGameChannelHandlerContextIt is a custom doubly linked list node (contains pre, nextpointer) DefaultGameChannelHandlerContextfor implementation, where each node encapsulates an event handlerChannelHandler ;
      • DefaultGameChannelHandlerContextAdd the linked list nodes GameChannelPipelineto get a doubly linked list , and different processing directions represent different operations (read/write).
      • GameChannelPipelineAllocate executable threads for the processors in turn for event monitoring and callback.
      • Among them Step1~Step4, it is the encapsulation of ChannelHandler, Step5and the thread setting listener is assigned to ChannelHandler
      • Step1 : YesUserEventContext processing class:AbstractGameChannelHandlerContext

        public class UserEventContext<T> {
                  
                  
        
            private T dataManager;
            private AbstractGameChannelHandlerContext ctx;
        
        
            public UserEventContext(T dataManager, AbstractGameChannelHandlerContext ctx) {
                  
                  
                super();
                this.dataManager= dataManager;
                this.ctx = ctx;
            }
            
            public T getDataManager() {
                  
                  
                return dataManager;
            }
            
            public AbstractGameChannelHandlerContext getCtx() {
                  
                  
                return ctx;
            }
        
        }
        
        
      • Step2 : AbstractGameChannelHandlerContextThe constructor of the event handler node

        public AbstractGameChannelHandlerContext(GameChannelPipeline pipeline, EventExecutor executor, String name, boolean inbound, boolean outbound) {
                  
                  
        
            this.name = ObjectUtil.checkNotNull(name, "name");
            this.pipeline = pipeline;
            this.executor = executor;
            this.inbound = inbound;
            this.outbound = outbound;
        }
        
      • Step3 : DefaultGameChannelHandlerContextIt is AbstractGameChannelHandlerContextthe implementation class, which encapsulateschannelHandler

        public class DefaultGameChannelHandlerContext extends AbstractGameChannelHandlerContext{
                  
                  
            private final GameChannelHandler handler;
            public DefaultGameChannelHandlerContext(GameChannelPipeline pipeline, EventExecutor executor, String name, GameChannelHandler channelHandler) {
                  
                  
                super(pipeline, executor, name,isInbound(channelHandler), isOutbound(channelHandler));//判断一下这个channelHandler是处理接收消息的Handler还是处理发出消息的Handler
                this.handler = channelHandler;
            }
        
            private static boolean isInbound(GameChannelHandler handler) {
                  
                  
                return handler instanceof GameChannelInboundHandler;
            }
        
            private static boolean isOutbound(GameChannelHandler handler) {
                  
                  
                return handler instanceof GameChannelOutboundHandler;
            }
        
            @Override
            public GameChannelHandler handler() {
                  
                  
                return this.handler;
            }
        
        }
        
      • Step4 : GameChannelPipelineDoubly linked list about the processor

          public class GameChannelPipeline {
                  
                  
              static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultChannelPipeline.class);
          
              private static final String HEAD_NAME = generateName0(HeadContext.class);
              private static final String TAIL_NAME = generateName0(TailContext.class);
          	
          	  private final GameChannel channel;
          	  private Map<EventExecutorGroup, EventExecutor> childExecutors;
          	  
          	  //GameChannelPipeline构造器
              protected GameChannelPipeline(GameChannel channel) {
                  
                  
                  this.channel = ObjectUtil.checkNotNull(channel, "channel");
          
                  tail = new TailContext(this);
                  head = new HeadContext(this);
          
                  head.next = tail;
                  tail.prev = head;
              }
             ...
          	  //生成处理器节点
              private AbstractGameChannelHandlerContext newContext(GameEventExecutorGroup group, boolean singleEventExecutorPerGroup, String name, GameChannelHandler handler) {
                  
                  
                    return new DefaultGameChannelHandlerContext(this, childExecutor(group, singleEventExecutorPerGroup), name, handler);
              }
              ...
              //将处理器节点添加到channelPipeline上
          	  public final GameChannelPipeline addFirst(GameEventExecutorGroup group, boolean singleEventExecutorPerGroup, String name, GameChannelHandler handler) {
                  
                  
                  final AbstractGameChannelHandlerContext newCtx;
                  synchronized (this) {
                  
                  
                      name = filterName(name, handler);
                      newCtx = newContext(group, singleEventExecutorPerGroup, name, handler);
                      addFirst0(newCtx);
                  }
              	  return this;
              }
        }
        
      • Step5 : Set the listener for eachchannelHandler , the method GameChannelPipelinein childExecutoris as follows:

        	private EventExecutor childExecutor(GameEventExecutorGroup group, boolean singleEventExecutorPerGroup) {
                  
                  
            if (group == null) {
                  
                  
                return null;
            }
        
            if (!singleEventExecutorPerGroup) {
                  
                  
                return group.next();
            }
            Map<EventExecutorGroup, EventExecutor> childExecutors = this.childExecutors;
            if (childExecutors == null) {
                  
                  
                // Use size of 4 as most people only use one extra EventExecutor.
                childExecutors = this.childExecutors = new IdentityHashMap<EventExecutorGroup, EventExecutor>(4);
            }
            // Pin one of the child executors once and remember it so that the same child executor
            // is used to fire events for the same channel.
            EventExecutor childExecutor = childExecutors.get(group);
            if (childExecutor == null) {
                  
                  
                childExecutor = group.next();
                childExecutors.put(group, childExecutor);
            }
            return childExecutor;
        }
        
    • Based on annotationsGetPlayerInfoEvent , you only need to identify the event class on the object method on the current event method, and the object method getPlayerInfoEventwill send the event to the above, and there will be a special event listener to monitorchannelPipeline during the processing :

      @UserEvent(GetPlayerInfoEvent.class)
      public void getPlayerInfoEvent(UserEventContext<PlayerManager> ctx, GetPlayerInfoEvent event, Promise<Object> promise) {
              
              
          GetPlayerByIdMsgResponse response = new GetPlayerByIdMsgResponse();
          Player player = ctx.getDataManager().getPlayer();
          response.getBodyObj().setPlayerId(player.getPlayerId());
          response.getBodyObj().setNickName(player.getNickName());
          Map<String, String> heros = new HashMap<>();
          player.getHeros().forEach((k, v) -> {
              
              // 复制处理一下,防止对象安全溢出。
              heros.put(k, v);
          });
          // response.getBodyObj().setHeros(this.player.getHeros());不要使用这种方式,它会把这个map传递到其它线程
          response.getBodyObj().setHeros(heros);
          promise.setSuccess(response);
      }
      

      UserEventContextThe function is the same as above, encapsulated ChannelHandler, and will be ChannelHandlerinserted GamePipelineinto it.

  • [Q] How to understand the process of the event system? (event firing - listener handles the event)
    Note :

    • When the service is started, the function module needs to register the interface for event monitoring , and the monitoring content includes the event and the event source (the object that the event generates) . When an event is triggered, these listening interfaces will be called , and the event and event source will be passed to the parameters of the interface, and then the received event will be processed in the listening interface .
    • Events can only flow from event publishers to event listeners , not back propagation.
      insert image description here

17、WebSocket

Refer to WebSocket knowledge point arrangement , polling/long polling (Comet)/long connection (SSE)/WebSocket (full-duplex) , simply build Websocket (java+vue)

  • [Q] What is websocket? What is the principle? (The technology used in HTML5 is a tcpfull-duplex communication protocol that supports real-time communication) , refer to WebSocket Baidu Encyclopedia , HTML5_ Baidu Encyclopedia

    Note

    • Before websocketit appeared, webthe interaction was generally a httpprotocol- based short or long connection ;

    • HTML5It is the abbreviation of HyperText Markup Language 5.HTML5 The technology HTML4.01combines relevant standards and innovations to meet the requirements of modern network development . It was officially released in 2008 . HTML5 is composed of different technologies, which have been widely used in the Internet, providing more standards to enhance web applications . HTML5A stable version was formed in 2012. On October 28, 2014, W3Cthe final version of HTML5 was released.

    • HTML5The protocol was defined in 2011 WebSocket( WebSocketthe communication protocol was regulated by IETF 6455 in 2011 and supplemented by RFC7936. WebSocket API is also W3Cdefined as a standard), which is essentially a tcp-based protocol , which can be achieved by handshaking through the status code of HTTP/1.1the protocol The full-duplex communication between the browser and the server can better save server resources and bandwidth , and enable more real-time communication.101

    • websocketIt is a brand-new persistence protocol, which is not httpa stateless protocol , and the protocol name is " ws";

  • [Q] What is the difference between socket and http? ( socketNot a protocol, but an API, which is TCP/IPthe encapsulation of the protocol)

    Note

    • socketis not a protocol:

      • HttpThe protocol is a simple object access protocol, corresponding to the application layer. HttpThe protocol is TCPconnection-based, mainly solving how to package data ;

        TCPThe protocol corresponds to the transport layer, which mainly solves how data is transmitted in the network ;

      • SocketIt is TCP/IPthe encapsulation of the protocol. SocketIt is not a protocol itself , but a calling interface (API) , through which the protocol Socketis implemented TCP/IP.

    • socketUsually it is a long connection:

      • HttpConnection: httpThe connection is the so-called short connection , and the client sends a request to the server, and the connection will be broken after the server responds.

      • socketConnection: socketThe connection is a so-called long connection . In theory, once the connection between the client and the server is established, it will not be disconnected actively ; however, the connection may be disconnected due to various environmental factors, such as: the server or client host is downdown , network failure, or there is no data transmission between the two for a long time , the network firewall may disconnect the link to release network resources.

        Therefore, when there is no data transmission in a connection, heartbeat messages need to be sentsocket in order to maintain a continuous connection . The specific heartbeat message format is defined by the developer.

  • [Q] What is the relationship between websocket and http? (The 3-way handshake is based on HTTPthe protocol, and the transmission is based on TCPthe channel, no HTTPprotocol is required)

    Note

    • Same point :

      • They are all based tcpon , and they are all reliable transmission protocols ;

      • Both are application layer protocols ;

    • Differences :

      • WebSocketIt is a two-way communication protocol, an analog Socketprotocol, which can send or receive information in two directions;

        butHTTP one-way;

      • WebSocketIt requires the browser and the server to shake hands to establish a connection

        Instead,http the browser initiates a connection to the server, which the server does not know about in advance.

    • Contact : WebSocketWhen establishing a handshake, data is HTTPtransmitted via . But after the establishment, the protocol is not required for actual transmissionHTTP ;

    • Summary (overall process):

      • First, the client initiates httpa request, and after three handshakes , a connection is established TCP; the supported version number and other information httpare stored in the request , such as: , , etc.;WebSocketUpgradeConnectionWebSocket-Version

      • Then, after receiving the handshake request from the client , the server also uses HTTPthe protocol to feed back data;

      • Finally, after receiving the message that the connection is successful, the client starts full-duplex communication by means of the TCP transmission channel .

  • [Q] The connection and difference between websocket and webrtc technology? (webrtc uses the websocket protocol in video streaming) , refer to WebRTC_Baidu Encyclopedia

    Note

    • Same point :

      • They are all based on socketprogramming and are used for front-end and back-end real-time communication technologies; they are all browser-based protocols;

      • The principle is that the data stream is transmitted to the server , and then the server distributes it . Both connections are long links ;

      • These two protocols put a lot of pressure on the server when they are used , because they will websocketonly be closed or closed when the other party closes the browser or the server actively closes webrtc;

    • Differences :

      • websocketEnsure that the two parties can send data to each other in real time, and you can decide what to send

      • webrtcThe camera is mainly obtained from the browser (the webpage test, the question brushing system is generally based on this technology) general webrtctechnology (audio and video collection, codec, network transmission and rendering, audio and video synchronization, etc.), is a protocol about the camera , transmitted in the network You need to cooperate with websockettechnology to use it . After all, it is useless to just get a camera, you have to send it to the server.

  • [Q] What is the problem with http? What methods of connection maintenance are included in instant messaging? (Problems in http: stateless protocol, time-consuming parsing of request headers (such as identity authentication information), one-way message sending) , refer to polling, long polling (comet), long connection (SSE), WebSocket

    Note

    • httpExisting problems:

      • httpIt is a stateless protocol . Every time a session is completed, the server does not know who the client is next time . It needs to know who the other party is before making a corresponding response. Therefore, it is extremely useful for real-time communication. big obstacle

      • httpThe protocol uses one request and one response, and each request and response carries a large number of headerheaders . For real-time communication, parsing the request header also takes a certain amount of time, so the efficiency is also lower

      • The most important thing is that httpthe protocol requires the client to actively send and the server to send passively , that is, one request and one response, and active sending cannot be achieved .

    • There are four common ways to implement instant messaging , namely: polling, long polling (comet), long connection (SSE), and WebSocket .

      • Polling (the client initiates a request within a time interval , and the client closes the connection after receiving the data):

        In order to implement push technology, many websites use polling technology. Polling is at a specific time interval (such as every 1 second), the client browser sends HTTPa request to the server , and then the server returns the latest data to the client browser.

        • Advantages : the back-end coding is relatively simple

        • Disadvantages : This traditional mode brings obvious disadvantages, that is, the client's browser needs to continuously send requests to the server. However, the HTTP request may contain a long header , and the real valid data may be only a small part. Obviously, this will waste a lot of bandwidth and other resources .

      • Long polling (the client initiates a request , the server maintains the connection , and the client closes the connection after receiving the data):

        The client initiates a request to the server, and the server keeps the connection open until data is sent to the client .

        • Advantages : Avoid frequent requests from the server when there is no information update, saving traffic

        • Disadvantages : Keeping the server connected all the time will consume resources , and it needs to maintain multiple threads at the same time , and the TCP connection that the server can carry is limited, so this kind of polling can easily lead to the upper limit of the connection .

      • Long connection (the connection is maintained through the channel , the client can disconnect, but the server cannot)

        After the connection between the client and the server is established, it will not be disconnected. When the client accesses the content on the server again, it will continue to use this connection channel

        • Advantages : messages arrive instantly, no useless requests are sent

        • Disadvantages : Like long polling, keeping the server connected will consume resources . If there are a large number of long connections, the consumption of the server will be huge, and there is an upper limit to the server's capacity, it is impossible to maintain unlimited long connections .

      • WebSocket (supports two-way real-time communication , if one of the client and server is disconnected, the connection will be interrupted)

        The client sends a request header ( ) carrying special informationUpgrade:WebSocket to the server to establish a connection. After the connection is established, the two parties can realize free real-time two-way communication .

        Advantages :

        • Less control overhead. After the connection is established, when data is exchanged between the server and the client, the packet headers used for protocol control are relatively small .
        • Stronger real-time performance. Since the protocol is full-duplex , the server can actively send data to the client at any time. Compared with HTTPthe request that needs to wait for the client to initiate a request for the server to respond , the delay is significantly less; even compared with Cometsimilar long polling, it can deliver data more times in a short period of time.
        • Stay connected . The difference HTTPis that Websocketa connection needs to be established first, which makes it a stateful protocol , and part of the state information can be omitted during subsequent communication. HTTPThe request may need to carry state information (such as identity authentication, etc.) in each request.

        Disadvantages : Relatively speaking, the development cost and difficulty are higher

      • WebSocketSummary comparison of polling, long polling, long connection and :

        Polling Long polling (Long-Polling) WebSocket Long connection (SSE)
        letter of agreement http http tcp http
        trigger method client (client) client (client) client, server (client, server) client, server (client, server)
        advantage Good compatibility, strong fault tolerance, simple implementation Conserves resources compared to short polling Full-duplex communication protocol, low performance overhead, high security, and strong scalability Easy to implement and low development cost
        shortcoming Poor security, occupying more memory resources and the number of requests Poor security, occupying more memory resources and the number of requests Secondary analysis is required to transmit data, which increases development cost and difficulty only for advanced browsers
        Delay Not real-time, the delay depends on the request interval Not real-time, the delay depends on the request interval real time Non-real-time, default 3 seconds delay, delay can be customized

Guess you like

Origin blog.csdn.net/qq_33934427/article/details/127747693