Web發展中通訊的方式有哪些

weixin_51578167發表於2020-11-23

Web發展中通訊方式

  • 簡單通訊
  • 不同請求
  • 複雜請求

案例實操

1 簡單通訊

  回顧 Socket 程式設計給我們最大的感受,是可以在多臺電腦之間進行資料的傳輸,這就是網路程式設計的開端和基礎,通過客戶端請求伺服器端通訊,直觀瞭解 Web 程式設計。

Server

/**
 * 服務端,接收客戶端請求並給出簡單的響應
 * @author Cushier
 *
 */
public class Server {
	
	public static void main(String[] args) throws IOException{
		// 建立伺服器,指定埠ServerSocket(int port)
		ServerSocket socket = new ServerSocket(8888);
		// 接收客戶端連線
		Socket client = socket.accept();
		System.out.println("******************");
		// 獲取資料的輸入流
		InputStream is = client.getInputStream();
		// 使用緩衝字元輸入流
		BufferedReader br = new BufferedReader(new InputStreamReader(is));
		String msg = "";
		while ((msg = br.readLine()) != null) {
			System.out.println(msg);
		}
		br.close();
	}
	
}

Client

/**
 * 客戶端:向伺服器傳送請求,併傳送簡單的訊息
 * @author Cushier
 *
 */
public class Client {
	
	public static void main(String[] args) throws UnknownHostException, IOException {
		// 建立客戶端 必須指定伺服器+埠
		Socket client = new Socket("localhost", 8888);
		// 傳送訊息 請求資源
		// 獲取輸出流
		OutputStream os = client.getOutputStream();
		// 使用緩衝字元輸出流
		BufferedWriter br = new BufferedWriter(new OutputStreamWriter(os));
		// 寫出訊息,傳送內容
		String msg = "Hello, I am Client, I need some resources";
		br.write(msg);
		br.close();
	}
	
}

服務端控制檯:

從上面的例子總結通訊條件如下:

  1. 需要有伺服器端(server):等待被請求,需要暴露 ip 和 port
  2. 需要有客戶端(client):主動發起請求,知曉服務端的 ip 和 port
  3. 通訊規則(協議):TCP/IP 協議

  ip 用於定位計算機;埠號(定位程式),用於標識程式的邏輯地址,不同程式的標誌;有效埠:0~65535,其中 0~1024 由系統使用或者保留埠,開發中建議使用 1024 以上的埠。

2 不同請求

Client

/**
 * 客戶端:向伺服器傳送請求,傳送不同的請求
 * @author Cushier
 *
 */
public class Client {
	
	public static void main(String[] args) throws IOException {
		// 通過系統預設型別的 SocketImpl 建立未連線套接字
		Socket socket = new Socket();
		// 此類實現 IP 套接字地址(IP 地址 + 埠號)。它還可以是一個對(主機名 + 埠號),在此情況下,將嘗試解析主機名
		SocketAddress address = new InetSocketAddress("localhost", 8898);
		// 將此套接字連線到伺服器,並指定一個超時值。或者不指定超時時間
		socket.connect(address, 1000);
		OutputStream os = socket.getOutputStream();
		os.write("time".getBytes());
		os.flush();
		socket.close();
	}
	
}

Server

/**
 * 服務端 
 * public class ServerSocketextends Object:此類實現伺服器套接字。
 * 伺服器套接字等待請求通過網路傳入。
 * 它基於該請求執行某些操作,然後可能向請求者返回結果。
 * 
 * @author Cushier
 *
 */
public class Server {
    
	public static void main(String[] args) throws IOException {
		// 建立繫結到特定埠的伺服器套接字。
		ServerSocket server = new ServerSocket(8898);

		// Socket accept() 偵聽並接受到此套接字的連線。
		Socket client = server.accept();
		System.out.println("接收到連線");

		InputStream is = client.getInputStream();
		BufferedInputStream bis = new BufferedInputStream(is);
		byte[] req = new byte[1024];
		// 接收客戶端請求
		int len = bis.read(req);
		String reqStr = new String(req, 0, len);
		System.out.println(reqStr);
		if (reqStr.equals("money")) {
			System.out.println("here's the money");
		} else if (reqStr.equals("time")) {
			System.out.println("you have so much time");
		}
		client.close();
		server.close();
	}
    
}

服務端控制檯:

3 複雜請求

Client

/**
 * 客戶端
 * 
 * @author Cushier
 *
 */
public class Client {
	
	public static void main(String[] args) throws IOException {
		// 通過系統預設型別的 SocketImpl 建立未連線套接字
		Socket socket = new Socket();
		// 此類實現 IP 套接字地址(IP 地址 + 埠號)。它還可以是一個對(主機名 + 埠號),在此情況下,將嘗試解析主機名
		SocketAddress address = new InetSocketAddress("localhost", 8898);
		// 將此套接字連線到伺服器,並指定一個超時值。或者不指定超時時間
		socket.connect(address, 1000);

		OutputStream os = socket.getOutputStream();
		os.write("money".getBytes());
		os.flush();
		// 接收響應,顯示結果
		InputStream is = socket.getInputStream();
		byte[] result = new byte[1024];
		int len = is.read(result);
		String resultStr = new String(result, 0, len);
		System.out.println(resultStr);
		socket.close();
	}
	
}

Server

/**
 * 服務端
 * @author Cushier
 *
 */
public class Server2 {
	
	public static void main(String[] args) throws IOException {
		// 建立繫結到特定埠的伺服器套接字。
		ServerSocket server = new ServerSocket(8898);

		// Socket accept() 偵聽並接受到此套接字的連線。
		Socket client = server.accept();
		System.out.println("接收到連線");
		InputStream is = client.getInputStream();
		BufferedInputStream bis = new BufferedInputStream(is);
		byte[] req = new byte[1024];
		// 接收客戶端請求
		int len = bis.read(req);
		String reqStr = new String(req, 0, len);
		System.out.println(reqStr);
		// 將接收到的請求封裝成物件,傳送給請求的類
		MyRequest request = new MyRequest();
		MyResponse response = new MyResponse();

		OutputStream os = client.getOutputStream();
		if (reqStr.equals("money")) {
			// 根據請求的資訊,構造處理的類
			MyServlet s1 = new ServletMoney();
			s1.service(request, response);
			// 通過client的響應,將結果響應回客戶端
			os.write("here's the money".getBytes());
			os.flush();
		} else if (reqStr.equals("time")) {
			// 根據請求的資訊,構造處理的類
			MyServlet s2 = new ServletTime();
			s2.service(request, response);
			// 通過client的響應,將結果響應回客戶端
			os.write("you have somuch time".getBytes());
			os.flush();
		}
		client.close();
		server.close();
	}
	
}

/*
 * 我是一個有要求的人,你請求的這個資源必須是滿足我要求格式的類,作用:防止混亂,方便呼叫 這是我的標準
 */
interface MyServlet {
	void service(MyRequest req, MyResponse resp);
}

class ServletMoney implements MyServlet {
	@Override
	public void service(MyRequest req, MyResponse resp) {
		// 做出力所能及的處理
	}
}

class ServletTime implements MyServlet {
	@Override
	public void service(MyRequest req, MyResponse resp) {
		// 做出力所能及的處理
	}
}

/*
 * 請求資訊都按規律封裝在該物件
 */
class MyRequest {
}

class MyResponse {
}

服務端控制檯:[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-MtJ94etz-1606099359234)(https://raw.githubusercontent.com/Cushier/picture/master/20190307152218.png)] 客戶端控制檯:

  隨著客戶需求越來越複雜,需要的功能越來越多,我們的伺服器端需要處理的請求越來越多,需要區分不同的請求,還需要按照不同請求進行請求資料的提取以及資源的分配和運算還有邏輯的處理,最後還需要響應給客戶端,這就使得伺服器端程式碼越來越複雜,實現越來越困難

  根據以往的經驗,雙方進行通訊只需要遵循一定的規則就可以很明確地知道各部分資料的含義,於是出現了網路更上層的應用協議(後面講的 HTTP 協議),規定伺服器端和客戶端通訊的規則。

  客戶端請求伺服器端和伺服器端響應客戶端,都按照固定的規則,那麼接收請求和響應資料這部分操作就可以固定下來,交給特定的一段程式碼來執行,從而減少伺服器端的程式碼量,於是出現了接下來說的伺服器

擴充套件

伺服器的出現

  當客戶端請求的資源越來越豐富,需求越來越複雜,程式的核心就應該放在解決業務和計算響應資料上,於是出現了伺服器統一接收客戶端資料進行處理並分發到不同的資源,由各個資源進行處理,最後結果交由伺服器響應。

  從上面的描述可以發現,現在所說的伺服器只是負責接收請求,對請求進行分發,以及最後將獲取的資料進行相應的固定框架,至於資料怎麼計算得出還得根據具體的業務需求編寫(填充)程式碼。在沒有業務需求的情況下就能將伺服器準備出來,現在市面上的伺服器有很多,比較常用的有:Tomcat、JBOOS、IBM 的 WebSphere、BEA的 WebLogic 以及 Apache 等。

相關文章