一. 前言在前上一章教程中,介紹了用SQL查詢本地文件。程式代碼請從這裡下載。 本章將在上一章的基礎上,進一步擴展程式。實際的生產環境中,一般查詢的文件都放在遠程的文件或數據伺服器上,下麵我將帶大家一步一步實現遠程查詢的程式。 註:1.本文針對初學Java的同學訓練學習思路,請不要太糾結於細節問題。 ...
一. 前言
在前上一章教程中,介紹了用SQL查詢本地文件。
程式代碼請從這裡下載。
本章將在上一章的基礎上,進一步擴展程式。
實際的生產環境中,一般查詢的文件都放在遠程的文件或數據伺服器上,
下麵我將帶大家一步一步實現遠程查詢的程式。
註:
1.本文針對初學Java的同學訓練學習思路,請不要太糾結於細節問題。
2.本文旨在達到拋磚引玉的效果,希望大家擴展本例子,以學到更多知識的精髓。
二. 寫給初學Java的同學
在介紹本章內容之前,首先介紹一下Java的學習方法。
相信大家在看本文的時候已經已經拿到了各種Java學習路徑,大體都是一樣。
我想說的是,不要讓知識的學習成為負擔,Java技術種類繁多,是無論如何也學不完的。
正確的學習方法是興趣驅動,實例驅動。
即通過一個簡單的實例,不斷加入所學知識進行擴展,最終擴展為一個大項目,達到系統學習,學以致用的效果。
三. 步入正題
話不多說,大家自己理解,下麵步入正題:
本章系統的流程如下:
【客戶端】
1.連接遠程伺服器。
2.向遠程伺服器發送查詢SQL。
3.將遠程伺服器反饋的查詢結果輸出。
【伺服器】
1.在指定埠監聽,等待客戶端連接。
2.有客戶端連接後,讀取客戶端傳來的SQL。
3.調用文件查詢模塊,查詢數據。
4.將查詢的數據反饋給客戶端。
5.轉到步驟1。
工程的結構如下:
其中文件查詢模塊復用上一章的代碼,在此不做講解。
我們著重介紹客戶端與伺服器通訊的過程。
要想與網路中的一臺機器的某個程式進行通訊,首先我們需要定位這台機器的某個程式。
IP地址標識了網路中唯一的機器,這台機器的不同的埠則標示了不同的程式。
所以,客戶端要知道連接伺服器的IP地址和埠號,來完成於伺服器的連接。
而伺服器程式之需要在特定的埠監聽,等待客戶端的連接。
伺服器連接成功後,即可通過輸入輸出流進行通訊。
通訊協議分為兩種TCP/IP協議和UDP協議:
前者能維持穩定的通訊,確保每一個發送的信息對方都收到。
後者只負責發送信息而不管對方有沒有收到。
比如文字通訊的軟體一般採用TCP/IP協議,因為要確保發送的每條消息對方都能收到。
音頻視頻通訊軟體一般採用UDP協議,因為缺了一點信息也不影響對聲音圖像的識別。
本項目我們採用TCP/IP協議,在Java中用ServerSocket和Socket封裝了TCP/IP協議,所以我們直接拿來用即可,感興趣的同學可以研究一下底層的實現。
四. 服務端程式
我們首先看單個客戶端與伺服器的通訊流程,如下圖所示:
多個客戶端連接後,如下圖所示:
所以,我們首先做一個類ClientThread,用來負責伺服器與客戶端通訊的線程,代碼如下:
1 /** 2 * 3 * @author http://www.java123.vip 4 * 5 */ 6 public class ClientThread implements Runnable{ 7 8 private Socket socket; 9 private BufferedReader br; 10 private PrintWriter pw; 11 12 public ClientThread(Socket socket) { 13 try { 14 15 // 創建輸入輸出流 16 InputStream is = socket.getInputStream(); 17 InputStreamReader isr = new InputStreamReader(is); 18 br = new BufferedReader(isr); 19 20 OutputStream os = socket.getOutputStream(); 21 OutputStreamWriter osw = new OutputStreamWriter(os); 22 pw = new PrintWriter(osw,true); 23 24 } catch (IOException e) { 25 e.printStackTrace(); 26 } 27 } 28 29 public void run() { 30 31 GetFile gf = new GetFile("c:/temp/"); 32 33 while(true) { 34 try { 35 36 // 讀取客戶端的一行信息 37 String message = br.readLine(); 38 System.out.println("get message:"+message); 39 40 // 用冒號(:)來分隔信息的頭與內容 41 String header = message.split(":")[0]; 42 String body = message.substring(message.indexOf(":")+1); 43 44 // 查詢請求 45 if(header.equals("query")) { 46 String result = gf.queryFile(body); 47 pw.println(result); 48 49 // 斷開連接請求 50 }else if(header.equals("bye")) { 51 if(socket != null) { 52 socket.close(); 53 } 54 break; 55 } 56 57 } catch(IOException e) { 58 e.printStackTrace(); 59 } catch (Exception e) { 60 e.printStackTrace(); 61 } 62 } 63 } 64 65 }
伺服器實現代碼如下:
1 /** 2 * 3 * @author http://www.java123.vip 4 * 5 */ 6 public class FileViewServer { 7 8 private int port; 9 10 public FileViewServer(int port) { 11 this.port = port; 12 } 13 14 /** 15 * 啟動伺服器 16 */ 17 public void startServer() { 18 try { 19 20 ServerSocket ss = new ServerSocket(port); 21 System.out.println("listening at port:"+port); 22 23 while(true) { 24 Socket s = ss.accept(); 25 System.out.println("get connection:"+s.getInetAddress().toString()); 26 27 // 得到連接後,啟動新線程負責通訊 28 ClientThread clientThread = new ClientThread(s); 29 new Thread(clientThread).start(); 30 } 31 32 } catch (IOException e) { 33 e.printStackTrace(); 34 } 35 } 36 37 public static void main(String[] args) { 38 FileViewServer fvs = new FileViewServer(8000); 39 fvs.startServer(); 40 } 41 }
五. 客戶端程式
我們需要做三個方法:
・連接伺服器方法
・斷開伺服器方法
・查詢遠程文件方法
代碼如下:
連接伺服器方法
1 private Socket socket; 2 private BufferedReader br; 3 private PrintWriter pw; 4 5 /** 6 * 連接遠程伺服器 7 * 8 * @param ip 9 * @param port 10 */ 11 public void connect(String ip, int port) { 12 try { 13 14 // 連接伺服器 15 socket = new Socket(ip, port); 16 17 // 創建輸入輸出流 18 InputStream is = socket.getInputStream(); 19 InputStreamReader isr = new InputStreamReader(is); 20 br = new BufferedReader(isr); 21 22 OutputStream os = socket.getOutputStream(); 23 OutputStreamWriter osw = new OutputStreamWriter(os); 24 pw = new PrintWriter(osw,true); 25 26 } catch (IOException e) { 27 e.printStackTrace(); 28 } 29 } 30
斷開伺服器方法
1 2 /** 3 * 斷開連接 4 */ 5 public void disConnect() { 6 try { 7 8 // 發送斷開連接請求 9 pw.println("bye:bye"); 10 socket.close(); 11 } catch (IOException e) { 12 e.printStackTrace(); 13 } 14 } 15
查詢遠程文件方法
1 /** 2 * 查詢 3 * 4 * @param sql 5 * @return 6 */ 7 public String query(String sql) { 8 9 StringBuffer result = new StringBuffer(""); 10 11 try { 12 13 // 發送查詢請求 14 pw.println("query:"+sql); 15 16 while(true) { 17 18 // 讀取查詢結果的每一行 19 String queryResultLine = br.readLine(); 20 21 // 讀到空字元串表示結果讀取完畢 22 if("".equals(queryResultLine)) { 23 break; 24 25 // 否則,把讀到的內容存起來 26 }else { 27 result.append(queryResultLine); 28 result.append("\n"); 29 } 30 } 31 } catch (IOException e) { 32 e.printStackTrace(); 33 } 34 35 // 返回查詢結果 36 return result.toString(); 37 } 38
六. 測試
最後我們來測試這個程式,測試代碼如下:
1 2 /** 3 * 測試 4 * @param args 5 */ 6 public static void main(String[] args) { 7 FileViewClient fvc = new FileViewClient(); 8 fvc.connect("127.0.0.1",8000); 9 10 String sql1 = "select * from abc.csv "; 11 String sql2 = "select id from abc.csv "; 12 String sql3 = "select id,username from abc.csv where id=2 "; 13 String sql4 = "select id,username from abc.csv where username=abc and password=aaa "; 14 String sql5 = "select id,username from abc.csv where username=abc and password=bbb "; 15 16 System.out.println("Execute:"+sql1); 17 System.out.println(fvc.query(sql1)); 18 19 System.out.println("Execute:"+sql2); 20 System.out.println(fvc.query(sql2)); 21 22 System.out.println("Execute:"+sql3); 23 System.out.println(fvc.query(sql3)); 24 25 System.out.println("Execute:"+sql4); 26 System.out.println(fvc.query(sql4)); 27 28 System.out.println("Execute:"+sql5); 29 System.out.println(fvc.query(sql5)); 30 31 fvc.disConnect(); 32 }
首先啟動伺服器,輸出如下:
listening at port:8000
啟動客戶端測試程式:
客戶端輸出如下:
Execute:select * from abc.csv
1,abc,aaa
2,def,bbb
3,xyz,ccc
Execute:select id from abc.csv
1
2
3
Execute:select id,username from abc.csv where id=2
2,def
Execute:select id,username from abc.csv where username=abc and password=aaa
1,abc
Execute:select id,username from abc.csv where username=abc and password=bbb
伺服器輸出如下:
listening at port:8000
get connection:/127.0.0.1
get message:query:select * from abc.csv
get message:query:select id from abc.csv
get message:query:select id,username from abc.csv where id=2
get message:query:select id,username from abc.csv where username=abc and password=aaa
get message:query:select id,username from abc.csv where username=abc and password=bbb
get message:bye:bye
完整代碼請在這裡下載
如有問題,大家來我的網站進行提問。
https://www.java123.vip/qa
七. 後續
本例為通過簡單的SQL語句查詢遠程存在的文件,大家可以擴展此程式,比如用線程池來管理線程,對於異常信息的處理等。
後續章節我將在此程式的基礎上,其支持JDBC介面,然後換成資料庫,並且一步一步實現ORM,Service,HTTP查詢等功能。
版權聲明:本教程版權歸java123.vip所有,禁止任何形式的轉載與引用。
原帖發表於:https://www.cnblogs.com/java123vip/p/9732445.html