Web服務(wù)器使用的是http協(xié)議,是基于“請求-響應(yīng)”的協(xié)議 ,http是無狀態(tài),每獲取一次數(shù)據(jù),都是執(zhí)行一次連接、發(fā)送請求消息、接收響應(yīng)消息、斷開的過程,是建立在tcp/ip協(xié)議上的可靠連接,關(guān)于如何是可靠的連接,也就是有些失敗重發(fā),校驗完整性等處理,這里就不詳談了。 Socket 庫是用于調(diào)用網(wǎng)絡(luò)功能的程序組件集合,使用現(xiàn)成的組件搭建應(yīng)用程序我們可以節(jié)省編程 工作量,同時多個程序使用相同的組件可以實現(xiàn)程序的標(biāo)準(zhǔn)化,在java中,我們常用的有:java.net.ServerSocket和java.net.Socket來進行網(wǎng)絡(luò)通信。 使用現(xiàn)有的組件進行網(wǎng)絡(luò)開發(fā),我們能夠屏蔽底層tcp握手的細(xì)節(jié)(想知道細(xì)節(jié)朋友的可以查看用 Wireshark 圖解 TCP 三次握手),簡化開發(fā)過程,抽象后的模型,如同下圖: 
下面通過簡單例子來說明利用現(xiàn)有組件開發(fā)的便捷,客戶端和服務(wù)端進行連接: 運行服務(wù)端代碼,如下:
public class ServerSocketConnect { public static void main(String[] args) throws IOException { try (ServerSocket serverSocket = new ServerSocket(9000, -1);) { //服務(wù)器端請求隊列數(shù)小于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); } }}打印結(jié)果,表明正常連接: 
接下來,我們用稍微復(fù)雜些的例子,實現(xiàn)web服務(wù)器,首先補充點基礎(chǔ)知識。 我們知道Http協(xié)議是應(yīng)用層協(xié)議,是用來規(guī)定應(yīng)用程序交互的數(shù)據(jù)格式的,網(wǎng)絡(luò)傳輸?shù)闹挥卸M制流,應(yīng)用程序如果想要明白這些二進制字節(jié)所表示的具體含義,就需要對這些字節(jié)流進行解析,那如何進行解析呢?這就要根據(jù)http協(xié)議的規(guī)則了,這個規(guī)則也就是描述,請求頭,請求體的位置,如何分隔等等,如下圖:
這是瀏覽器請求信息的一部分,當(dāng)發(fā)送給服務(wù)端應(yīng)用程序的時候,網(wǎng)絡(luò)傳輸只有字節(jié)流,服務(wù)器會將字節(jié)進行編碼,如果是英文通信,由于編碼唯一,服務(wù)器可以準(zhǔn)確的還原信息,如果有中文,那么服務(wù)器必須知道如何進行編碼,這個問題在后面討論。 當(dāng)服務(wù)器完成編碼工作后,會還原如圖所示的請求信息,那么服務(wù)器要如何應(yīng)用?很簡單,按照http協(xié)議,進行字符串拆分,拆分出請求方法,get、post等、uri響應(yīng)資源的位置、請求參數(shù)以及客戶端的cookie等等,這也是大家所知tomcat的實現(xiàn)。廢話不說了,上代碼。
服務(wù)端程序,監(jiān)聽端口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;/** * 服務(wù)端處理程序 * @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("接收數(shù)據(jù)完畢。"); returnResponseInfo(socket); System.out.println("數(shù)據(jù)發(fā)送完畢。"); } } } } /** * 返回響應(yīng)信息 * @param socket * @throws IOException */ private static void returnResponseInfo(Socket socket) throws IOException { OutputStream ops = socket.getOutputStream(); //http協(xié)議規(guī)范,空行隔開頭和體-/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()); }}運行程序,接下來,我們通過瀏覽器進行訪問:
服務(wù)端打印:
到這里,應(yīng)該明白了吧,很簡單,而這就是web服務(wù)器的原型。
新聞熱點
疑難解答