Java basic syntax_ 24_ Network programming 02

Posted by uNF on Fri, 14 Jan 2022 22:20:30 +0100

1.NIO

1.1 NIO channel client [application]

  • Client implementation steps

    1. Open channel
    2. Specify the IP and port number
    3. Write data
    4. Release resources
  • Sample code

    public class NIOClient {
        public static void main(String[] args) throws IOException {
            //1. Open the channel
            SocketChannel socketChannel = SocketChannel.open();
    
            //2. Specify the IP and port number
            socketChannel.connect(new InetSocketAddress("127.0.0.1",10000));
    
            //3. Write data
            ByteBuffer byteBuffer = ByteBuffer.wrap("A little cold hair is made first".getBytes());
            socketChannel.write(byteBuffer);
    
            //4. Release resources
            socketChannel.close();
        }
    }
    

1.2 NIO channel server [application]

  • NIO channel

    • Server channel

      It is only responsible for establishing, not transmitting data

    • Client channel

      Establish and transfer data to the server

    • buffer

      The data sent by the client is in the buffer

    • The client channel created inside the server channel

      Equivalent to an extension of the client channel used to transfer data

  • Server implementation steps

    1. Open a server channel
    2. Bind the corresponding port number
    3. The channel is blocked by default and needs to be set to non blocking
    4. There is no guard at this time, so you need to often check whether there is a connection sent?
    5. If a client is connected, create another client channel inside the server channel, which is equivalent to the extension of the client channel
    6. Get the data passed by the client and put the data in the buffer byteBuffer1
    7. Write back data to the client
    8. Release resources
  • Sample code

    public class NIOServer {
        public static void main(String[] args) throws IOException {
    //        1. Open a server channel
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
    //        2. Bind the corresponding port number
            serverSocketChannel.bind(new InetSocketAddress(10000));
    //        3. The channel is blocked by default and needs to be set to non blocking
                //If true is passed, the channel is set to blocked channel Default value
                //If false is passed, the channel is set to a non blocking channel
            serverSocketChannel.configureBlocking(false);
    //        4. There is no guard at this time, so you need to often check whether there is a connection sent?
            while (true) {
    //        5. If a client is connected, create another client channel inside the server channel, which is equivalent to the extension of the client channel
                //At this time, the channel has been set to non blocking
                //Therefore, when calling the method, if there is a client to connect, a SocketChannel object will be created
                //If there is no client to connect when calling the method, it will return a null
                SocketChannel socketChannel = serverSocketChannel.accept();
                //System.out.println(socketChannel);
                if(socketChannel != null){
    //        6. The client passes the buffer to the server through the channel to the extension channel socketChannel
    //        7. The server creates an empty buffer to load data and output it
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                    //Get the passed data and put them into the byteBuffer buffer
                    //Return value:
                        //Positive number: indicates the number of valid bytes read this time
                        //0: indicates that no valid bytes are read this time
                        //-1: it means the end is read
                    int len = socketChannel.read(byteBuffer);
                    System.out.println(new String(byteBuffer.array(),0,len));
                  //8. Release resources
                    socketChannel.close();
                }
            }
        }
    }
    

1.3 NIO channel practice [application]

  • client

    • Implementation steps

      1. Open channel
      2. Specify the IP and port number
      3. Write data
      4. Read data written back by the server
      5. Release resources
    • Sample code

      public class Clinet {
          public static void main(String[] args) throws IOException {
              // 1. Open the channel
              SocketChannel socketChannel = SocketChannel.open();
              // 2. Specify the IP and port number
              socketChannel.connect(new InetSocketAddress("127.0.0.1",10000));
              // 3. Write data
              ByteBuffer byteBuffer1 = ByteBuffer.wrap("Eat my old sun".getBytes());
              socketChannel.write(byteBuffer1);
        		// Manual write end flag
              socketChannel.shutdownOutput();
      
              System.out.println("The data has been written to the server");
              // 4. Read the data written back by the server
              ByteBuffer byteBuffer2 = ByteBuffer.allocate(1024);
              int len;
              while((len = socketChannel.read(byteBuffer2)) != -1){
                  byteBuffer2.flip();
                  System.out.println(new String(byteBuffer2.array(),0,len));
                  byteBuffer2.clear();
              }
              // 5. Release resources
              socketChannel.close();
          }
      }
      
  • Server

    • Implementation steps

      1. Open a server channel
      2. Bind the corresponding port number
      3. The channel is blocked by default and needs to be set to non blocking
      4. There is no guard at this time, so you need to often check whether there is a connection sent?
      5. If a client is connected, create another client channel inside the server channel, which is equivalent to the extension of the client channel
      6. Get the data passed by the client and put the data in the buffer byteBuffer1
      7. Write back data to the client
      8. Release resources
    • Sample code

      public class Sever {
          public static void main(String[] args) throws IOException {
              // 1. Open a server channel
              ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
              // 2. Bind the corresponding port number
              serverSocketChannel.bind(new InetSocketAddress(10000));
              // 3. The channel is blocked by default and needs to be set to non blocking
              serverSocketChannel.configureBlocking(false);
              // 4. There is no guard at this time, so you need to often check whether there is a connection sent?
              while(true){
                  //  5. If a client is connected, create another client channel inside the server channel, which is equivalent to the extension of the client channel
                  SocketChannel socketChannel = serverSocketChannel.accept();
                  if(socketChannel != null){
                      System.out.println("At this time, there is a client to connect");
                      // 6. Get the data passed by the client and put the data in the buffer byteBuffer1
                      ByteBuffer byteBuffer1 = ByteBuffer.allocate(1024);
                      //socketChannel.read(byteBuffer1);
                      int len;
                      //For buffers
                          //If you get data from add data - > flip
                          //If you get data from ---- > add data clear
                      while((len = socketChannel.read(byteBuffer1)) != -1){
                          byteBuffer1.flip();
                          System.out.println(new String(byteBuffer1.array(),0,len));
                          byteBuffer1.clear();
                      }
      
                      System.out.println("Data reception completed,Ready to start writing data back to the client");
                      // 7. Write back data to the client
                      ByteBuffer byteBuffer2 = ByteBuffer.wrap("Ouch,It hurts!!!".getBytes());
                      socketChannel.write(byteBuffer2);
                      // 8. Release resources
                      socketChannel.close();
                  }
              }
          }
      }
      

1.4 NIO channel practice optimization [application]

  • Existing problems

    When the client channel obtained by the server is read, if the end tag is not read, it will be blocked all the time

  • Solution

    Set the client channel obtained internally by the server to non blocking

  • Sample code

    // client
    public class Clinet {
        public static void main(String[] args) throws IOException {
            SocketChannel socketChannel = SocketChannel.open();
    
            socketChannel.connect(new InetSocketAddress("127.0.0.1",10000));
    
            ByteBuffer byteBuffer1 = ByteBuffer.wrap("Eat my old sun".getBytes());
            socketChannel.write(byteBuffer1);
    
            System.out.println("The data has been written to the server");
    
            ByteBuffer byteBuffer2 = ByteBuffer.allocate(1024);
            int len;
            while((len = socketChannel.read(byteBuffer2)) != -1){
                System.out.println("Client receives write back data");
                byteBuffer2.flip();
                System.out.println(new String(byteBuffer2.array(),0,len));
                byteBuffer2.clear();
            }
            socketChannel.close();
        }
    }
    // Server
    public class Sever {
        public static void main(String[] args) throws IOException {
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
    
            serverSocketChannel.bind(new InetSocketAddress(10000));
    
            serverSocketChannel.configureBlocking(false);
    
            while(true){
                SocketChannel socketChannel = serverSocketChannel.accept();
                if(socketChannel != null){
                    System.out.println("At this time, there is a client to connect");
                  	// Set the client channel obtained internally by the server to non blocking
                    socketChannel.configureBlocking(false);
                    //Get the data passed by the client and put the data in the buffer byteBuffer1
                    ByteBuffer byteBuffer1 = ByteBuffer.allocate(1024);
                    //socketChannel.read(byteBuffer1);
                    int len;
                    //For buffers
                        //If you get data from add data - > flip
                        //If you get data from ---- > add data clear
                    while((len = socketChannel.read(byteBuffer1)) > 0){
                        System.out.println("The server receives and sends data");
                        byteBuffer1.flip();
                        System.out.println(new String(byteBuffer1.array(),0,len));
                        byteBuffer1.clear();
                    }
    
                    System.out.println("Data reception completed,Ready to start writing data back to the client");
    
                    ByteBuffer byteBuffer2 = ByteBuffer.wrap("Ouch,It hurts!!!".getBytes());
                    socketChannel.write(byteBuffer2);
    
                    socketChannel.close();
                }
            }
        }
    }
    

1.5NIO selector [understanding]

  • summary

    The selector can monitor the status of the channel and multiplex

    [the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-zktu4NMM-1627131407903)(.\img__ selector overview. png)]

    [the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-yCxP1hKf-1627131407907)(.\img(_ selector multiplexing. png)]

  • Selector object

    • Selector

      Selector object

    • SelectionKey

      Bound key

    • SelectableChannel

      Channels that can use selectors

      • SocketChannel
      • ServerSocketChannel

1.6 NiO selector rewriting server [application]

  • Implementation steps

    1. Open a server channel

    2. Bind the corresponding port number

    3. The channel is blocked by default and needs to be set to non blocking

    4. Open a selector (doorman)

    5. Bind the selector to the server channel and monitor whether the server is ready

    6. If there is a client to connect, the uncle will traverse all the server channels. Whoever is ready will connect
      After connecting, create a client extension channel inside the server channel

    7. If the client transmits the data, the uncle will traverse all the extension channels. Who is ready and who will receive the data

      [the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-SnI6cKIf-1627131407910)(.\img_selector rewrites the server. png)]

  • code implementation

    // client
    public class Clinet {
        public static void main(String[] args) throws IOException {
            SocketChannel socketChannel = SocketChannel.open();
    
            socketChannel.connect(new InetSocketAddress("127.0.0.1",10000));
    
            ByteBuffer byteBuffer1 = ByteBuffer.wrap("Eat my old sun".getBytes());
            socketChannel.write(byteBuffer1);
    
            System.out.println("The data has been written to the server");
    
            ByteBuffer byteBuffer2 = ByteBuffer.allocate(1024);
            int len;
            while((len = socketChannel.read(byteBuffer2)) != -1){
                System.out.println("Client receives write back data");
                byteBuffer2.flip();
                System.out.println(new String(byteBuffer2.array(),0,len));
                byteBuffer2.clear();
            }
            socketChannel.close();
        }
    }
    // Server
    public class Server {
        public static void main(String[] args) throws IOException {
            //1. Open the server channel
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            //2. Bind this channel to a port
            serverSocketChannel.bind(new InetSocketAddress(10000));
            //3. Set the channel to non blocking
            serverSocketChannel.configureBlocking(false);
            //4. Open a selector
            //Selector --- selector
    //        SelectionKey --- the token returned after binding the channel
      //      SelectableChannel --- a channel that can use a selector
            Selector selector = Selector.open();
            //5. Bind selector and server channel
            serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
    
            while(true){
                System.out.println("11");
                //The selector monitors the status of the client channel
                //6. The return value indicates how many clients are connected at this time
                int count = selector.select();
                System.out.println("222");
                if(count != 0){
                    System.out.println("There is a client to connect");
                    //7. It will traverse all server channels See who is ready, who is ready, let who connect
                    //Get the tokens of all server channels, put them into a collection, and return the collection
                    Set<SelectionKey> selectionKeys = selector.selectedKeys();
                    Iterator<SelectionKey> iterator = selectionKeys.iterator();
                    while(iterator.hasNext()){
                        //selectionKey indicates the token of each server channel in turn
                        SelectionKey selectionKey = iterator.next();
                        if(selectionKey.isAcceptable()){
                            //A ready server channel can be obtained through a token
                            ServerSocketChannel ssc = (ServerSocketChannel) selectionKey.channel();
                            //Extended channel of client
                            SocketChannel socketChannel = ssc.accept();
                            //Set the client extension channel to non blocking
                            socketChannel.configureBlocking(false);
                            socketChannel.register(selector,SelectionKey.OP_READ);
                            //When the client connects, all the steps have been completed
                        }else if(selectionKey.isReadable()){
                            //The current channel is ready for reading (extended channel)
                            SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                            ByteBuffer byteBuffer1 = ByteBuffer.allocate(1024);
                            //socketChannel.read(byteBuffer1);
                            int len;
                            while((len = socketChannel.read(byteBuffer1)) > 0){
                                byteBuffer1.flip();
                                System.out.println(new String(byteBuffer1.array(),0,len));
                                byteBuffer1.clear();
                            }
                            //Write back data to client
                            socketChannel.write(ByteBuffer.wrap("Oh, hey, it hurts!!!".getBytes()));
                            socketChannel.close();
                        }
                        iterator.remove();
                    }
                }
            }
        }
    }
    

2.HTTP protocol

2.1 overview [understanding]

Hypertext Transfer Protocol (the concept of hypertext is being studied by Java Web), which is based on TCP/IP protocol and is the protocol of network application layer.

Composed of request and response, it is a standard client and server model

2.2 URL [understanding]

  • summary

    Uniform resource locator, such as http://bbs.itheima.com/forum.php

    The complete format is http://bbs.itheima.com:80/forum.php

  • Explain in detail

    [the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-woyMT8zP-1627131407911)(.\img_url.png)]

2.3 use of bag grabbing tools [ application ]

  • Use steps

    1. Press F12 or right-click in the blank space of Google browser web page, and click Check to call up the tool

    2. Click network to enter the interface of viewing network related information

    3. At this time, a request is initiated in the browser for access, and the information related to the request and response will be displayed in the tool

      [the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-7BYOOWCV-1627131407912)(.\img_ packet capture. png)]

2.4 request information [ understanding ]

  • form

    • Request line
    • Request header
    • Request blank line
    • Request body
  • Request line

    • format

      [the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-FCQZl96S-1627131407913)(.\img_ request line format. png)]

    • Request mode

      GET,POST,HEAD,PUT,DELETE,CONNECT,OPTIONS,TRACE,PATCH

      Among them, GET and POST are mostly used

    • URI

      Request resource path, uniform resource identifier

      [the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-LgQfm5oi-1627131407913)(.\img_Uri diagram. png)]

    • Protocol version

      • HTTP1.0: a separate connection needs to be established for each request and response
      • HTTP1.1: Support long connection
  • Request header

    • format

      [the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-mC8OtgYR-1627131407914)(.\img_ request header diagram. png)]

    • Request header name

      • Host: used to specify the server address of the request
      • Connection: the value is keep alive, indicating that a persistent connection is required
      • User agent: client information
      • Accept: Specifies the content type that the client can receive
      • Accept encoding: Specifies the compression encoding type of content returned by the server that the browser can support
      • Accept language: the language acceptable to the browser

      [the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-zfDjkGtW-1627131407914)(.\img_ request header example. png)]

  • Summary

    [the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-3JMgcltx-1627131407915)(.\img_ request information summary. png)]

2.5 response information [understanding]

  • form

    • Response line
    • Response header
    • Response blank line
    • Responder
  • Response line

    • format

      [the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (IMG umjavmvp-1627131407915) (. \ img \ 11_ response header format. png)]

    • Protocol version

      • HTTP1.0: a separate connection needs to be established for each request and response
      • HTTP1.1: Support long connection
    • Response status code

      • 1xx: indication information (indicating that the request has been received and processing continues)
      • 2xx: successful (indicates that the request has been successfully received, understood and accepted)
      • 3xx: request redirection (further operation is required to complete the request)
      • 4xx: client error (the request has syntax error or the request cannot be implemented)
      • 5xx: server side error (the server failed to implement the legal request)
    • status information

      • 200 ok
      • 404 Not Found
      • 500 Internal Server Error
  • Response header

    • Response header name

      • Content type: tells the client the network media type of the actually returned content (Internet media type, also known as MIME type)
    • Response header value

      • Text / HTML ---- > text type
      • Image / PNG ---- > PNG format file
      • Image / jpeg ---- > JPG format file

      [the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-974A9uQp-1627131407916)(.\img response header example. png)]

  • Summary

    [the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-TWIxJlER-1627131407916)(.\img_ summary of response information. png)]

3.HTTP server

3.1 requirements [understanding]

  • Write server-side code to parse the browser's request and respond to the browser's data

3.2 environment construction [understanding]

  • Implementation steps

    • Write the HttpServer class to receive requests from browsers
    • The code for obtaining the connection can be extracted into a class separately
  • code implementation

    // Server code
    public class HttpServer {
        public static void main(String[] args) throws IOException {
            //1. Open the server channel
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            //2. Bind this channel to a port
            serverSocketChannel.bind(new InetSocketAddress(10000));
            //3. Set the channel to non blocking
            serverSocketChannel.configureBlocking(false);
            //4. Open a selector
            Selector selector = Selector.open();
    
            //5. Bind selector and server channel
            serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
    
            while(true){
                //6. The selector will monitor the status of the channel
                int count = selector.select();
                if(count != 0){
                    //7. It will traverse all server channels See who is ready, who is ready, let who connect
                    //Get the tokens of all server channels, put them into a collection, and return the collection
                    Set<SelectionKey> selectionKeys = selector.selectedKeys();
                    Iterator<SelectionKey> iterator = selectionKeys.iterator();
                    while(iterator.hasNext()){
                        //selectionKey indicates the token of each server channel in turn
                        SelectionKey selectionKey = iterator.next();
                        if(selectionKey.isAcceptable()){
                            //Get connection
                            AcceptHandler acceptHandler = new AcceptHandler();
                            acceptHandler.connSocketChannel(selectionKey);
                        }else if(selectionKey.isReadable()){
                           
                        }
                        //After the task is processed, remove the SelectionKey from the collection
                        iterator.remove();
                    }
                }
            }
        }
    }
    // Extract the code to get the connection into this class
    public class AcceptHandler {
    
        public SocketChannel connSocketChannel(SelectionKey selectionKey){
            try {
                //Get the ready server channel
                ServerSocketChannel ssc = (ServerSocketChannel) selectionKey.channel();
                SocketChannel socketChannel = ssc.accept();
                //Set to non blocking state
                socketChannel.configureBlocking(false);
                //Register the socketChannel with the selector
                socketChannel.register(selectionKey.selector(), SelectionKey.OP_READ);
                return socketChannel;
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    

3.3 obtain request information and analyze [understand]

  • Implementation steps

    • Encapsulate the request information into the HttpRequest class
    • Define the method in the class to obtain the request information and parse it
  • code implementation

    /**
     * The class used to encapsulate the requested data
     */
    public class HttpRequest {
        private String method; //Request mode
        private String requestURI; //Requested uri
        private String version;   //http protocol version
    
        private HashMap<String,String> hm = new HashMap<>();//All request headers
    
        //Parse -- get the request data and parse it
        public void parse(SelectionKey selectionKey){
            try {
                SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
    
                StringBuilder sb = new StringBuilder();
                //Create a buffer
                ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                int len;
                //Cyclic reading
                while((len = socketChannel.read(byteBuffer)) > 0){
                    byteBuffer.flip();
                    sb.append(new String(byteBuffer.array(),0,len));
                    //System.out.println(new String(byteBuffer.array(),0,len));
                    byteBuffer.clear();
                }
                //System.out.println(sb);
                parseHttpRequest(sb);
    
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        //Parsing data in http request protocol
        private void parseHttpRequest(StringBuilder sb) {
            //1. You need to change StringBuilder into a string first
            String httpRequestStr = sb.toString();
            //2. Get each row of data
            String[] split = httpRequestStr.split("\r\n");
            //3. Get request line
            String httpRequestLine = split[0];//GET / HTTP/1.1
            //4. Cut according to the space to get three parts of the request line
            String[] httpRequestInfo = httpRequestLine.split(" ");
            this.method = httpRequestInfo[0];
            this.requestURI = httpRequestInfo[1];
            this.version = httpRequestInfo[2];
            //5. Operate each request header
            for (int i = 1; i < split.length; i++) {
                String httpRequestHeaderInfo = split[i];//Host: 127.0.0.1:10000
                String[] httpRequestHeaderInfoArr = httpRequestHeaderInfo.split(": ");
                hm.put(httpRequestHeaderInfoArr[0],httpRequestHeaderInfoArr[1]);
            }
    
        }
    
        public String getMethod() {
            return method;
        }
    
        public void setMethod(String method) {
            this.method = method;
        }
    
        public String getRequestURI() {
            return requestURI;
        }
    
        public void setRequestURI(String requestURI) {
            this.requestURI = requestURI;
        }
    
        public String getVersion() {
            return version;
        }
    
        public void setVersion(String version) {
            this.version = version;
        }
    
        public HashMap<String, String> getHm() {
            return hm;
        }
    
        public void setHm(HashMap<String, String> hm) {
            this.hm = hm;
        }
    
        @Override
        public String toString() {
            return "HttpRequest{" +
                    "method='" + method + '\'' +
                    ", requestURI='" + requestURI + '\'' +
                    ", version='" + version + '\'' +
                    ", hm=" + hm +
                    '}';
        }
    }
    

3.4 response data to browser [understand]

  • Implementation steps

    • Encapsulate the response information in the HttpResponse class
    • Define the method, encapsulate the response information and give the browser response data
  • code implementation

    public class HttpResponse {
        private String version; //Protocol version
        private String status;  //Response status code
        private String desc;    //Description information of status code
    
        //Response header data
        private HashMap<String, String> hm = new HashMap<>();
    
        private HttpRequest httpRequest;  //We will make some judgments based on the requested data later
    
        //Method of responding data to browser
        public void sendStaticResource(SelectionKey selectionKey) {
            //1. Assign a value to the response line
            this.version = "HTTP/1.1";
            this.status = "200";
            this.desc = "ok";
            //2. Splice the response line into a separate string / / HTTP/1.1 200 ok
            String responseLine = this.version + " " + this.status + " " + this.desc + "\r\n";
    
            //3. Assign a value to the response header
            hm.put("Content-Type", "text/html;charset=UTF-8");
    
            //4. Splice all response headers into a single string
            StringBuilder sb = new StringBuilder();
            Set<Map.Entry<String, String>> entries = hm.entrySet();
            for (Map.Entry<String, String> entry : entries) {
                sb.append(entry.getKey()).append(": ").append(entry.getValue()).append("\r\n");
            }
    
            //5. Respond to blank lines
            String emptyLine = "\r\n";
    
            //6. The response line, response header and empty response line are spliced into a large string
            String responseLineStr = responseLine + sb.toString() + emptyLine;
    
            try {
                //7. Write the above three to the browser
                SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                ByteBuffer byteBuffer1 = ByteBuffer.wrap(responseLineStr.getBytes());
                socketChannel.write(byteBuffer1);
    
                //8. Operate the responder separately
                //Because the response body is not necessarily a string in the future
                //It may be a file, so operate separately
                String s = "Ouch,Oh, my God,Finally finished.";
                ByteBuffer byteBuffer2 = ByteBuffer.wrap(s.getBytes());
                socketChannel.write(byteBuffer2);
    
                //9. Release resources
                socketChannel.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public String getVersion() {
            return version;
        }
    
        public void setVersion(String version) {
            this.version = version;
        }
    
        public String getStatus() {
            return status;
        }
    
        public void setStatus(String status) {
            this.status = status;
        }
    
        public String getDesc() {
            return desc;
        }
    
        public void setDesc(String desc) {
            this.desc = desc;
        }
    
        public HashMap<String, String> getHm() {
            return hm;
        }
    
        public void setHm(HashMap<String, String> hm) {
            this.hm = hm;
        }
    
        public HttpRequest getHttpRequest() {
            return httpRequest;
        }
    
        public void setHttpRequest(HttpRequest httpRequest) {
            this.httpRequest = httpRequest;
        }
    
        @Override
        public String toString() {
            return "HttpResponse{" +
                    "version='" + version + '\'' +
                    ", status='" + status + '\'' +
                    ", desc='" + desc + '\'' +
                    ", hm=" + hm +
                    ", httpRequest=" + httpRequest +
                    '}';
        }
    }
    

3.5 code optimization [understanding]

  • Implementation steps

    • Respond to different data according to different request resource paths
    • Server robustness processing
    • Access nonexistent resource processing
  • code implementation

    /**
     * Task processing class for receiving connections
     */
    public class AcceptHandler {
    
        public SocketChannel connSocketChannel(SelectionKey selectionKey){
            try {
                //Get the ready server channel
                ServerSocketChannel ssc = (ServerSocketChannel) selectionKey.channel();
                SocketChannel socketChannel = ssc.accept();
                //Set to non blocking state
                socketChannel.configureBlocking(false);
                //Register the socketChannel with the selector
                socketChannel.register(selectionKey.selector(), SelectionKey.OP_READ);
                return socketChannel;
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    /**
     * Class to receive client requests
     */
    public class HttpServer {
        public static void main(String[] args) throws IOException {
            //1. Open the server channel
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            //2. Bind this channel to a port
            serverSocketChannel.bind(new InetSocketAddress(10000));
            //3. Set the channel to non blocking
            serverSocketChannel.configureBlocking(false);
            //4. Open a selector
            Selector selector = Selector.open();
            //5. Bind selector and server channel
            serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
    
            while(true){
                //6. The selector will monitor the status of the channel
                int count = selector.select();
                if(count != 0){
                    //7. It will traverse all server channels See who is ready, who is ready, let who connect
                    //Get the tokens of all server channels, put them into a collection, and return the collection
                    Set<SelectionKey> selectionKeys = selector.selectedKeys();
                    Iterator<SelectionKey> iterator = selectionKeys.iterator();
                    while(iterator.hasNext()){
                        //selectionKey indicates the token of each server channel in turn
                        SelectionKey selectionKey = iterator.next();
                        if(selectionKey.isAcceptable()){
                            //Get connection
                            AcceptHandler acceptHandler = new AcceptHandler();
                            acceptHandler.connSocketChannel(selectionKey);
    
                        }else if(selectionKey.isReadable()){
                            //Read data
                            HttpRequest httpRequest = new HttpRequest();
                            httpRequest.parse(selectionKey);
                            System.out.println("http The requested data is ---->" + httpRequest);
    
                            if(httpRequest.getRequestURI() == null || "".equals(httpRequest.getRequestURI())){
                                selectionKey.channel();
                                continue;
                            }
                            System.out.println("...Data analysis completed,Prepare response data....");
    
                            //Response data
                            HttpResponse httpResponse = new HttpResponse();
                            httpResponse.setHttpRequest(httpRequest);
                            httpResponse.sendStaticResource(selectionKey);
                        }
                        //After the task is processed, remove the SelectionKey from the collection
                        iterator.remove();
                    }
                }
            }
        }
    }
    /**
     * The class used to encapsulate the requested data
     */
    public class HttpRequest {
        private String method; //Request mode
        private String requestURI; //Requested uri
        private String version;   //http protocol version
    
        private HashMap<String,String> hm = new HashMap<>();//All request headers
    
        //Parse -- get the request data and parse it
        public void parse(SelectionKey selectionKey){
            try {
                SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
    
                StringBuilder sb = new StringBuilder();
                //Create a buffer
                ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                int len;
                //Cyclic reading
                while((len = socketChannel.read(byteBuffer)) > 0){
                    byteBuffer.flip();
                    sb.append(new String(byteBuffer.array(),0,len));
                    //System.out.println(new String(byteBuffer.array(),0,len));
                    byteBuffer.clear();
                }
                //System.out.println(sb);
                parseHttpRequest(sb);
    
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
      
        //Parsing data in http request protocol
        private void parseHttpRequest(StringBuilder sb) {
            //1. You need to change StringBuilder into a string first
            String httpRequestStr = sb.toString();
            if(!(httpRequestStr == null || "".equals(httpRequestStr))){
                //2. Get each row of data
                String[] split = httpRequestStr.split("\r\n");
                //3. Get request line
                String httpRequestLine = split[0];//GET / HTTP/1.1
                //4. Cut according to the space to get three parts of the request line
                String[] httpRequestInfo = httpRequestLine.split(" ");
                this.method = httpRequestInfo[0];
                this.requestURI = httpRequestInfo[1];
                this.version = httpRequestInfo[2];
                //5. Operate each request header
                for (int i = 1; i < split.length; i++) {
                    String httpRequestHeaderInfo = split[i];//Host: 127.0.0.1:10000
                    String[] httpRequestHeaderInfoArr = httpRequestHeaderInfo.split(": ");
                    hm.put(httpRequestHeaderInfoArr[0],httpRequestHeaderInfoArr[1]);
                }
            }
        }
    
        public String getMethod() {
            return method;
        }
    
        public void setMethod(String method) {
            this.method = method;
        }
    
        public String getRequestURI() {
            return requestURI;
        }
    
        public void setRequestURI(String requestURI) {
            this.requestURI = requestURI;
        }
    
        public String getVersion() {
            return version;
        }
    
        public void setVersion(String version) {
            this.version = version;
        }
    
        public HashMap<String, String> getHm() {
            return hm;
        }
    
        public void setHm(HashMap<String, String> hm) {
            this.hm = hm;
        }
    
        @Override
        public String toString() {
            return "HttpRequest{" +
                    "method='" + method + '\'' +
                    ", requestURI='" + requestURI + '\'' +
                    ", version='" + version + '\'' +
                    ", hm=" + hm +
                    '}';
        }
    }
    /**
     * Class used to encapsulate response data
     */
    public class HttpResponse {
        private String version; //Protocol version
        private String status;  //Response status code
        private String desc;    //Description information of status code
    
        //Response header data
        private HashMap<String, String> hm = new HashMap<>();
    
        private HttpRequest httpRequest;  //We will make some judgments based on the requested data later
    
        //Method of responding data to browser
        public void sendStaticResource(SelectionKey selectionKey) {
            //1. Assign a value to the response line
            this.version = "HTTP/1.1";
            this.status = "200";
            this.desc = "ok";
    
            //3. Assign a value to the response header
            //Get the URI of the browser request first
            String requestURI = this.getHttpRequest().getRequestURI();
            if(requestURI != null){
    
                File file = new File(WEB_APP_PATH + requestURI);
                //Determine whether this path exists
                if(!file.exists()){
                    this.status = "404";
                    this.desc = "NOT FOUNG";
                }
    
                if("200".equals(this.status)){
                    if("/".equals(requestURI)){
                        hm.put("Content-Type", "text/html;charset=UTF-8");
                    }else if("/favicon.ico".equals(requestURI)){
                        hm.put("Content-Type", "image/x-icon");
                    }else if("/a.txt".equals(requestURI)){
                        hm.put("Content-Type", "text/html;charset=UTF-8");
                    }else if("/1.jpg".equals(requestURI)){
                        hm.put("Content-Type", "image/jpeg");
                    }else if("/1.png".equals(requestURI)){
                        hm.put("Content-Type", "image/png");
                    }
                }else{
                    hm.put("Content-Type", "text/html;charset=UTF-8");
                }
    
            }
    
            //2. Splice the response line into a separate string / / HTTP/1.1 200 ok
            String responseLine = this.version + " " + this.status + " " + this.desc + "\r\n";
    
            //4. Splice all response headers into a single string
            StringBuilder sb = new StringBuilder();
            Set<Map.Entry<String, String>> entries = hm.entrySet();
            for (Map.Entry<String, String> entry : entries) {
                sb.append(entry.getKey()).append(": ").append(entry.getValue()).append("\r\n");
            }
    
            //5. Respond to blank lines
            String emptyLine = "\r\n";
    
            //6. The response line, response header and empty response line are spliced into a large string
            String responseLineStr = responseLine + sb.toString() + emptyLine;
    
            try {
                //7. Write the above three to the browser
                SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                ByteBuffer byteBuffer1 = ByteBuffer.wrap(responseLineStr.getBytes());
                socketChannel.write(byteBuffer1);
    
                //8. Operate the responder separately
                //Because the response body is not necessarily a string in the future
                //It may be a file, so operate separately
               // String s = "Oh, my God, it's finally finished.";
                byte [] bytes = getContent();
                ByteBuffer byteBuffer2 = ByteBuffer.wrap(bytes);
                socketChannel.write(byteBuffer2);
    
                //9. Release resources
                socketChannel.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public static final String WEB_APP_PATH = "mynio\\webapp";
        private byte[] getContent() {
            try {
                //1. Get the URI requested by the browser
                String requestURI = this.getHttpRequest().getRequestURI();
                if(requestURI != null){
    
                    if("200".equals(this.status)){
                        //2. Judge the URI of the request and respond to different things according to different URIs
                        if("/".equals(requestURI)){
                            String s = "Ouch,Oh, my God,Finally finished.";
                            return s.getBytes();
                        }else/* if("/favicon.ico".equals(requestURI))*/{
                            //Get an ico file
                            FileInputStream fis = new FileInputStream(WEB_APP_PATH + requestURI);
                            //Turn the ico file into a byte array and return
                            return IOUtils.toByteArray(fis);
                        }
                    }else{
                        return "The accessed resource does not exist".getBytes();
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            return new byte[0];
        }
    
        public String getVersion() {
            return version;
        }
    
        public void setVersion(String version) {
            this.version = version;
        }
    
        public String getStatus() {
            return status;
        }
    
        public void setStatus(String status) {
            this.status = status;
        }
    
        public String getDesc() {
            return desc;
        }
    
        public void setDesc(String desc) {
            this.desc = desc;
        }
    
        public HashMap<String, String> getHm() {
            return hm;
        }
    
        public void setHm(HashMap<String, String> hm) {
            this.hm = hm;
        }
    
        public HttpRequest getHttpRequest() {
            return httpRequest;
        }
    
        public void setHttpRequest(HttpRequest httpRequest) {
            this.httpRequest = httpRequest;
        }
    
        @Override
        public String toString() {
            return "HttpResponse{" +
                    "version='" + version + '\'' +
                    ", status='" + status + '\'' +
                    ", desc='" + desc + '\'' +
                    ", hm=" + hm +
                    ", httpRequest=" + httpRequest +
                    '}';
        }
    }
    

Topics: Java http NIO https url