This is the 12th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

blocking

Design of blocking modes

  • In blocking mode, all methods cause the thread to pause
    • ServerSocketChannel. Will accept without the thread is stopped when the connection is established, even after the client to the server sends the message that the server also can not accept, until there is a new client connection service side, no longer block on the accept method.
    • Socketchannel. read suspends the thread if there is no more data to read in the channel, and even if a new client sends a connection request to the server, it will not accept it until the read is complete and no longer blocks the read method
    • Blocking is essentially a pause in the thread. The pause does not consume CPU, but the thread is idle
  • Under single thread, blocking methods affect each other and can hardly work properly, requiring multithreading support
  • If there are too many connections, it will inevitably result in OOM (out of memory). If there are too many threads, it will degrade performance due to frequent context switching
    • Thread pool technology can be used to reduce the number of threads and thread context switches, but it does not cure the symptoms. If many connections are established, but idle for a long time, all threads in the thread pool will be blocked. Therefore, it is not suitable for long connections, only for short connections

For NIO blocking, the single-threaded server code has the following steps:

  1. Open server ByteBuffer to store data
  2. Create a server ServerSocketChannel
  3. ServerSocketChannel Binding listening port
  4. Create a connection set that holds all user connection Socketchannels
  5. Accept establishes a connection with the client. SocketChannel communicates with the client
  6. Receives data sent by the client and iterates through the collection to see if there is any data sent by the user
public class NIOServer {
    public static void main(String[] args) throws IOException {
        ByteBuffer buffer = ByteBuffer.allocate(100);
        try(ServerSocketChannel serverSocket = ServerSocketChannel.open())
        {
            serverSocket.bind(new InetSocketAddress(8080));
            List<SocketChannel> channels = new ArrayList<>();
            while(true)
            {
                SocketChannel sc = serverSocket.accept();
                channels.add(sc);

                for(SocketChannel asc :channels) { asc.read(buffer); buffer.flip(); ByteBufferUtil.debugAll(buffer); buffer.clear(); }}}catch(IOException e) { e.printStackTrace(); }}}Copy the code

For clients, it is easier to create a SocketChannel, connect to a server port, and then send data over the channel using write

public class NIOClient {
    public static void main(String[] args) {
        try(SocketChannel socketChannel = SocketChannel.open())
        {
            socketChannel.connect(new InetSocketAddress("localhost".8080));
            System.out.println("connecting...");
        }catch(IOException e) { e.printStackTrace(); }}}Copy the code

Analysis of blocking patterns

Previous blog Java network programming (a) – simple C/S procedures – Digging gold (juejin. Cn) introduced using Socket can also achieve similar effects, but the use of Socket needs to get input stream and output stream, no convenient use of channels, but he still does not change the blocking mode of serious problems: When no new clients attempt to connect to the server, the server program blocks the Accept method and does not read messages from other clients. When no user sends a message, the server program blocks the read method and does not receive a message from a new client.

non-blocking

Non-blocking mode design

The above analysis blocks in two places in blocking mode — the Accept method and the read method, thus providing a non-blocking state in NIO:

  • You can set the access connection to non-blocking through the configureBlocking(false) method of ServerSocketChannel. Accept returns null if there is no connection
  • You can set reading data from the channel to non-blocking through SocketChannel’s configureBlocking(false) method. If there is no data to read in the channel, read returns -1
public class NIOServer {
    public static void main(String[] args) throws IOException {
        ByteBuffer buffer = ByteBuffer.allocate(100);
        try(ServerSocketChannel serverSocket = ServerSocketChannel.open())
        {
            serverSocket.bind(new InetSocketAddress(8080));

            List<SocketChannel> channels = new ArrayList<>();

            while(true)
            {
                // Set to non-blocking mode, return null if there is no connection, no thread blocking
                serverSocket.configureBlocking(false);

                SocketChannel sc = serverSocket.accept();

                if(sc! =null)
                {
                    System.out.println("----new client----");
                    channels.add(sc);
                }


                for (SocketChannel asc :channels)
                {
                    // Set to non-blocking mode. If there is no data in the channel, 0 is returned and the thread is not blocked
                    asc.configureBlocking(false);
                    int readsize = asc.read(buffer);
                    if(readsize>0){ buffer.flip(); ByteBufferUtil.debugAll(buffer); buffer.clear(); }}}}catch(IOException e) { e.printStackTrace(); }}}Copy the code

Analysis of non-blocking modes

It is true that non-blocking mode does not block, at least not affect the business, but from the performance analysis, this non-blocking state will occur CPU idle, that is, may be a while loop, occupy CPU resources.