Web服務器使用的是http協議,是基于“請求-響應”的協議 ,http是無狀態,每獲取一次數據,都是執行一次連接、發送請求消息、接收響應消息、斷開的過程,是建立在tcp/ip協議上的可靠連接,關于如何是可靠的連接,也就是有些失敗重發,校驗完整性等處理,這里就不詳談了。 Socket 庫是用于調用網絡功能的程序組件集合,使用現成的組件搭建應用程序我們可以節省編程 工作量,同時多個程序使用相同的組件可以實現程序的標準化,在java中,我們常用的有:java.net.ServerSocket和java.net.Socket來進行網絡通信。 使用現有的組件進行網絡開發,我們能夠屏蔽底層tcp握手的細節(想知道細節朋友的可以查看用 Wireshark 圖解 TCP 三次握手),簡化開發過程,抽象后的模型,如同下圖:
下面通過簡單例子來說明利用現有組件開發的便捷,客戶端和服務端進行連接: 運行服務端代碼,如下:
public class ServerSocketConnect { public static void main(String[] args) throws IOException { try (ServerSocket serverSocket = new ServerSocket(9000, -1);) { //服務器端請求隊列數小于0為50 while (true) { try (Socket socket = serverSocket.accept();) { System.out.PRintln(socket.getRemoteSocketAddress());//打印客戶端連接信息 } } } }}運行客戶端代碼,如下:
public class ClientSocketConnect { public static void main(String[] args) throws IOException { SocketAddress socketAddress = new InetSocketAddress("localhost", 9000); try(Socket socket = new Socket()) { socket.connect(socketAddress); } }}打印結果,表明正常連接:
接下來,我們用稍微復雜些的例子,實現web服務器,首先補充點基礎知識。 我們知道Http協議是應用層協議,是用來規定應用程序交互的數據格式的,網絡傳輸的只有二進制流,應用程序如果想要明白這些二進制字節所表示的具體含義,就需要對這些字節流進行解析,那如何進行解析呢?這就要根據http協議的規則了,這個規則也就是描述,請求頭,請求體的位置,如何分隔等等,如下圖: 這是瀏覽器請求信息的一部分,當發送給服務端應用程序的時候,網絡傳輸只有字節流,服務器會將字節進行編碼,如果是英文通信,由于編碼唯一,服務器可以準確的還原信息,如果有中文,那么服務器必須知道如何進行編碼,這個問題在后面討論。 當服務器完成編碼工作后,會還原如圖所示的請求信息,那么服務器要如何應用?很簡單,按照http協議,進行字符串拆分,拆分出請求方法,get、post等、uri響應資源的位置、請求參數以及客戶端的cookie等等,這也是大家所知tomcat的實現。廢話不說了,上代碼。
服務端程序,監聽端口9000,等待客戶端請求。
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.net.ServerSocket;import java.net.Socket;/** * 服務端處理程序 * @author guanjie * */public class ServerSocketConnect { public static void main(String[] args) throws IOException, InterruptedException { try (ServerSocket serverSocket = new ServerSocket(9000, 2);) { while (true) { try (Socket socket = serverSocket.accept();) { System.out.println("獲取連接[ address: " + socket.getInetAddress() + ", port: " + socket.getPort() + " ]"); printRequestInfo(socket) System.out.println("接收數據完畢。"); returnResponseInfo(socket); System.out.println("數據發送完畢。"); } } } } /** * 返回響應信息 * @param socket * @throws IOException */ private static void returnResponseInfo(Socket socket) throws IOException { OutputStream ops = socket.getOutputStream(); //http協議規范,空行隔開頭和體-/r/n ops.write("HTTP/1.1 200 OK/r/n/r/n <h1>hello</h1>".getBytes("utf-8")); } /** * 打印請求信息 * @throws IOException */ private static void printRequestInfo(Socket socket) throws IOException { InputStream is = socket.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is, "utf-8")); System.out.println(br.readLine()); }}運行程序,接下來,我們通過瀏覽器進行訪問: 服務端打印:
到這里,應該明白了吧,很簡單,而這就是web服務器的原型。
新聞熱點
疑難解答