1. http protocol
Request packet resolution
- The first part: request line, request type, resource path and HTTP version.
- The second part: the request header, the part immediately after the request line (i.e. the first line), is used to describe the additional information to be used by the server.
- The third part: blank line. The blank line after the request header is required. There must be a new line between the request header and the data body.
- The fourth part: the request data is also called the main body, and any data can be added. The request content for this example is empty.
Response packet analysis
- Part one: status line. HTTP version, status code, status message.
- The second part: the response header, which is immediately after the status line (i.e. the first line), is used to describe the additional information to be used by the server.
- The third part: blank line, the blank line behind the head is necessary. There must be a line break between the header and the data body.
- The fourth part: response text. You can add any data. The response body of this example is "Hello World".
Response status code
- 1xx (temporary response): a status code that indicates a temporary response and requires the requester to continue the operation.
- 2xx (success): status code indicating that the request was processed successfully.
- 3xx (redirect): indicates that further action is required to complete the request. Usually, these status codes are used for redirection.
- 4xx (request error): these status codes indicate that the request may be in error, preventing the server from processing.
- 5xx (server error): these status codes indicate that the server encountered an internal error while trying to process the request. These errors can be from the server itself, not the request.
2. BIO
1. Meaning of blocking IO
- Blocking IO: when a resource is not available, IO requests are blocked until the feedback results (data or timeout).
- Non blocking IO: when the resource is unavailable, the IO request returns immediately, and the returned data indicates that the resource is unavailable.
- Synchronous IO: the application blocks the status of sending or receiving data until the data is successfully transmitted or returned to failure.
- Asynchronous IO: the application returns immediately after sending or receiving data. The actual processing is performed asynchronously.
Blocking / non blocking is the way to get resources, and synchronous / asynchronous is the logical design of how to deal with resources.
API used in the code: ServerSocket ා accept, InputStream read are blocked APIs. In the underlying API of the operating system, the default Socket operations are Blocking, and the send/recv and other interfaces are Blocking.
Blocking causes a thread to process only one network connection when processing network I/O.
3. BIO network programming
1. Client code
public class BIOClient { private static Charset charset = Charset.forName("UTF-8"); public static void main(String[] args) throws IOException { Socket s = new Socket("localhost", 8080); OutputStream out = s.getOutputStream(); Scanner scanner = new Scanner(System.in); System.out.println("Please input:"); String msg = scanner.nextLine(); out.write(msg.getBytes(charset)); // Block, write complete scanner.close(); s.close(); } }
2. Preliminary server code
public class BIOServer1 { public static void main(String[] args) throws IOException { ServerSocket ss = new ServerSocket(8080); System.out.println("Server started successfully!"); while (! ss.isClosed()) { Socket request = ss.accept(); // block System.out.println("New connection received:" + request.toString()); try { // Receiving data, printing InputStream inputStream = request.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "utf-8")); String msg; while ((msg = reader.readLine()) != null) { // No data, blocking if (msg.length() == 0) { break; } System.out.println(msg); } System.out.println("Received data from:" + request.toString()); } finally { request.close(); } } ss.close(); } }
3. Use thread pool to receive multiple connections
// Multithreading support public class BIOServer2 { private static ExecutorService threadPool = Executors.newCachedThreadPool(); public static void main(String[] args) throws IOException { ServerSocket ss = new ServerSocket(8080); System.out.println("Server started successfully!"); while (! ss.isClosed()) { Socket request = ss.accept(); System.out.println("New connection received:" + request.toString()); threadPool.execute(() -> { // Receiving data, printing try { InputStream inputStream = request.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "utf-8")); String msg; while ((msg = reader.readLine()) != null) { if (msg.length() == 0) { break; } System.out.println(msg); } System.out.println("Received data from:" + request.toString()); } catch (IOException e) { e.printStackTrace(); } finally { try { request.close(); } catch (IOException e) { e.printStackTrace(); } } }); } ss.close(); } }
4. The server handles browser requests
public class BIOServer3 { private static ExecutorService threadPool = Executors.newCachedThreadPool(); public static void main(String[] args) throws IOException { ServerSocket ss = new ServerSocket(8080); System.out.println("Server started successfully"); while (! ss.isClosed()) { Socket request = ss.accept(); System.out.println("New connection received:" + request.toString()); threadPool.execute(() -> { try { InputStream inputStream = request.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "utf-8")); String msg; while ((msg = reader.readLine()) != null) { if (msg.length() == 0) { break; } System.out.println(msg); } System.out.println("Received data from:" + request.toString()); // Response result 200 OutputStream outputStream = request.getOutputStream(); outputStream.write("HTTP/1.1 200 OK\r\n".getBytes()); outputStream.write("Content-Length: 11\r\n\r\n".getBytes()); outputStream.write("Hello World".getBytes()); outputStream.flush(); } catch (IOException e) { e.printStackTrace(); } finally { try { request.close(); } catch (IOException e) { e.printStackTrace(); } } }); } ss.close(); } }