一. 前言
在前上一章教程中, 介绍了用 SQL 查询本地文件.
程序代码请从这里 http://www.java123.vip/ 下载.
本章将在上一章的基础上, 进一步扩展程序.
实际的生产环境中, 一般查询的文件都放在远程的文件或数据服务器上,
下面我将带大家一步一步实现远程查询的程序.
注:
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, 用来负责服务器与客户端通讯的线程, 代码如下:
- /**
- *
- * @author http://www.java123.vip
- *
- */
- public class ClientThread implements Runnable{
- private Socket socket;
- private BufferedReader br;
- private PrintWriter pw;
- public ClientThread(Socket socket) {
- try {
- // 创建输入输出流
- InputStream is = socket.getInputStream();
- InputStreamReader isr = new InputStreamReader(is);
- br = new BufferedReader(isr);
- OutputStream os = socket.getOutputStream();
- OutputStreamWriter osw = new OutputStreamWriter(os);
- pw = new PrintWriter(osw,true);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- public void run() {
- GetFile gf = new GetFile("c:/temp/");
- while(true) {
- try {
- // 读取客户端的一行信息
- String message = br.readLine();
- System.out.println("get message:"+message);
- // 用冒号 (:) 来分隔信息的头与内容
- String header = message.split(":")[0];
- String body = message.substring(message.indexOf(":")+1);
- // 查询请求
- if(header.equals("query")) {
- String result = gf.queryFile(body);
- pw.println(result);
- // 断开连接请求
- }else if(header.equals("bye")) {
- if(socket != null) {
- socket.close();
- }
- break;
- }
- } catch(IOException e) {
- e.printStackTrace();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- }
服务器实现代码如下:
- /**
- *
- * @author http://www.java123.vip
- *
- */
- public class FileViewServer {
- private int port;
- public FileViewServer(int port) {
- this.port = port;
- }
- /**
- * 启动服务器
- */
- public void startServer() {
- try {
- ServerSocket ss = new ServerSocket(port);
- System.out.println("listening at port:"+port);
- while(true) {
- Socket s = ss.accept();
- System.out.println("get connection:"+s.getInetAddress().toString());
- // 得到连接后, 启动新线程负责通讯
- ClientThread clientThread = new ClientThread(s);
- new Thread(clientThread).start();
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- public static void main(String[] args) {
- FileViewServer fvs = new FileViewServer(8000);
- fvs.startServer();
- }
- }
五. 客户端程序
我们需要做三个方法:
连接服务器方法
断开服务器方法
查询远程文件方法
代码如下:
连接服务器方法
- private Socket socket;
- private BufferedReader br;
- private PrintWriter pw;
- /**
- * 连接远程服务器
- *
- * @param ip
- * @param port
- */
- public void connect(String ip, int port) {
- try {
- // 连接服务器
- socket = new Socket(ip, port);
- // 创建输入输出流
- InputStream is = socket.getInputStream();
- InputStreamReader isr = new InputStreamReader(is);
- br = new BufferedReader(isr);
- OutputStream os = socket.getOutputStream();
- OutputStreamWriter osw = new OutputStreamWriter(os);
- pw = new PrintWriter(osw,true);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
断开服务器方法
- /**
- * 断开连接
- */
- public void disConnect() {
- try {
- // 发送断开连接请求
- pw.println("bye:bye");
- socket.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
查询远程文件方法
- /**
- * 查询
- *
- * @param sql
- * @return
- */
- public String query(String sql) {
- StringBuffer result = new StringBuffer("");
- try {
- // 发送查询请求
- pw.println("query:"+sql);
- while(true) {
- // 读取查询结果的每一行
- String queryResultLine = br.readLine();
- // 读到空字符串表示结果读取完毕
- if("".equals(queryResultLine)) {
- break;
- // 否则, 把读到的内容存起来
- }else {
- result.append(queryResultLine);
- result.append("\n");
- }
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- // 返回查询结果
- return result.toString();
- }
六. 测试
最后我们来测试这个程序, 测试代码如下:
- /**
- * 测试
- * @param args
- */
- public static void main(String[] args) {
- FileViewClient fvc = new FileViewClient();
- fvc.connect("127.0.0.1",8000);
- String sql1 = "select * from abc.CSV";
- String sql2 = "select id from abc.CSV";
- String sql3 = "select id,username from abc.CSV where id=2";
- String sql4 = "select id,username from abc.CSV where username=abc and password=aaa";
- String sql5 = "select id,username from abc.CSV where username=abc and password=bbb";
- System.out.println("Execute:"+sql1);
- System.out.println(fvc.query(sql1));
- System.out.println("Execute:"+sql2);
- System.out.println(fvc.query(sql2));
- System.out.println("Execute:"+sql3);
- System.out.println(fvc.query(sql3));
- System.out.println("Execute:"+sql4);
- System.out.println(fvc.query(sql4));
- System.out.println("Execute:"+sql5);
- System.out.println(fvc.query(sql5));
- fvc.disConnect();
- }
首先启动服务器, 输出如下:
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
完整代码请在这里 http://java123.vip/ 下载
如有问题, 大家来我的网站进行提问.
https://www.java123.vip/qa
七. 后续
本例为通过简单的 SQL 语句查询远程存在的文件, 大家可以扩展此程序, 比如用线程池来管理线程, 对于异常信息的处理等.
后续章节我将在此程序的基础上, 其支持 JDBC 接口, 然后换成数据库, 并且一步一步实现 ORM,Service,HTTP 查询等功能.
来源: https://www.cnblogs.com/java123vip/p/9732445.html