1.NIO
1.1 NIO channel client [application]
-
Client implementation steps
- Open channel
- Specify the IP and port number
- Write data
- 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
- Open a server channel
- Bind the corresponding port number
- The channel is blocked by default and needs to be set to non blocking
- There is no guard at this time, so you need to often check whether there is a connection sent?
- If a client is connected, create another client channel inside the server channel, which is equivalent to the extension of the client channel
- Get the data passed by the client and put the data in the buffer byteBuffer1
- Write back data to the client
- 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
- Open channel
- Specify the IP and port number
- Write data
- Read data written back by the server
- 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
- Open a server channel
- Bind the corresponding port number
- The channel is blocked by default and needs to be set to non blocking
- There is no guard at this time, so you need to often check whether there is a connection sent?
- If a client is connected, create another client channel inside the server channel, which is equivalent to the extension of the client channel
- Get the data passed by the client and put the data in the buffer byteBuffer1
- Write back data to the client
- 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
-
Open a server channel
-
Bind the corresponding port number
-
The channel is blocked by default and needs to be set to non blocking
-
Open a selector (doorman)
-
Bind the selector to the server channel and monitor whether the server is ready
-
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 -
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
-
Press F12 or right-click in the blank space of Google browser web page, and click Check to call up the tool
-
Click network to enter the interface of viewing network related information
-
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 + '}'; } }