- 浏览: 20290 次
- 性别:
- 来自: 北京
最新评论
纸上得来终觉浅,绝知此事要躬行。—陆游
意思是说,从书本上得来的知识终归是浅薄的,要透彻的认知事务还必须亲自实践。
这句话告诉我们,除了要掌握好理论知识,还必须得亲自动手做实践,来证明结论。理论引导实践,实践推翻理论。正是这个道理!
前面三章,我们对Socket编程进行了一个比较全面的阐述,相信大家对Socket编程有了一个比较全面的认识,今天我们来实现一个实例,加深对Socket编程的理解。
1、实例:实现一个质数判断程序。即
客户端在控制台输入一个数字,服务端告诉客户端该数字是否是质数。
1)服务端程序流程:
(1)获取客户端输入的数据
(2)做判断处理
(3)返回处理结果
2)客户端程序流程:
(1)用户在控制台输入数字
(2)获取用户输入的数字并发送给服务端
(3)获取服务端响应结果,并输出在控制台中
3)说明:
(1)质数(素数):除了1和本身,没有其他公约数
(2)为节省流量,服务端程序不直接告诉客户端结果,而是通过规定的协议,返回状态码。
协议规定为(这个协议自己任意定):0 是质数, 1 不是质数, 2 输入非法
2、代码实现:
1)服务端代码:
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * 服务端:判断客户端输入的数字是否是质数 * 步骤: * 1.获取客户端输入的数据 * 2.做判断处理 * 3.返回处理结果 * * @author Sam * */ public class PrimeNumServer { // 服务端监听的端口号 private static final int PORT = 10000; /** * @param args */ public static void main(String[] args) { try { ServerSocket ss = new ServerSocket(PORT); System.out.println("Server 等待客户端接入..."); while (true) { // 监听客户端请求 Socket socket = ss.accept(); // 监听到有客户端接入,则开启一个子线程处理请求 new Thread(new Task(socket)).start(); } } catch (IOException e) { e.printStackTrace(); } } /** * 处理Socket请求任务类 * */ private static class Task implements Runnable { private Socket socket; private BufferedReader buffRreader; private BufferedWriter buffWriter; public Task(Socket socket) { try { this.socket = socket; // 字符读取流 this.buffRreader = new BufferedReader( new InputStreamReader(socket.getInputStream())); // 字符写入流 this.buffWriter = new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())); } catch (IOException e) { e.printStackTrace(); } } @Override public void run() { handlRequest(); } /** * 处理请求 */ private void handlRequest() { try { // 接收客户端数据 String data = receive(); // 处理逻辑 String result = checkIsPrimeNum(data); // 发送响应结果 send(result); } finally { StreamUtils.close(buffRreader, buffWriter); close(socket); } } /** * 检查是否是质数,根据协议规定,返回状态码 * @param numStr * @return 0 是质数, 1 不是质数, 2 输入非法 */ private String checkIsPrimeNum(String numStr) { // 先判断输入的是否是数字 boolean isNumber = isNumber(numStr); // 是数字,进一步判断是否是质数(素数) if (isNumber) { int number = Integer.parseInt(numStr); return isPrimeNumber(number); } else {// 输入非数字,则认为是非法的 return "2"; } } /** * 判断是否是数字 * @param numStr * @return */ private boolean isNumber(String numStr) { Pattern pattern = Pattern.compile("[0-9]*"); Matcher matcher = pattern.matcher(numStr); return matcher.matches(); } /** * 判断是否是质数 * @param number * @return 0 是质数, 1 不是质数, 2 输入非法 */ private String isPrimeNumber(int number) { if (number < 2) {// 如果数字小于2,则认为是非法 return "2"; } else { // 真正做质数的判断逻辑 for (int i=2; i<=number-1; i++) { /* * 用2至number-1之间的所有数去整除number, * 如果有一个能被整除,说明是number非质数 */ if (number % i == 0) { return "1"; } } return "0"; } } /** * 接收客户端发送过来的数据 * @return */ private String receive() { try { return buffRreader.readLine(); } catch (IOException e) { e.printStackTrace(); } return null; } /** * 向客户端发送响应结果 * @param result */ private void send(String result) { try { buffWriter.write(result); buffWriter.newLine();// 写一个换行符 buffWriter.flush(); } catch (IOException e) { e.printStackTrace(); } } } /** * 关闭客户端Socket * @param socket */ private static void close(Socket socket) { if (socket != null) { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } socket = null; } } }
服务端代码分析:
1、在isNumber(String numStr)方法中判断一个字符串是否是数字,用了一个正则匹配,匹配规则为:字符串是由0~9之间的数组成,并且可以出现零次或多次;有关更详细的匹配规则可以参看JDK文档中的:java.util.regex.Pattern类
2、在isPrimeNumber(int number)方法中判断一个数是否是质数:
用2至number-1之间的所有数去整除number,
1)如果有一个能被整除说明是number非质数;
2)如果所有的数都不未来整除,则说明是质数。
3、为了避免代码冗余,在finally子句中使用了一个StreamUtils流工具类来关闭资源,最后会把这个工具类的代码贴上。
2)客户端代码:
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.Socket; /** * 客户端:输入一个数字 * 步骤: * 1.用户在控制台输入数字 * 2.获取用户输入的数字并发送给服务端 * 3.获取服务端响应结果 * * @author Sam * */ public class PrimeNumClient { // 主机 private static final String HOST = "127.0.0.1"; // 端口号 private static final int PORT = 10000; private static Socket socket; private static BufferedReader buffReader; private static BufferedWriter buffWriter; private static BufferedReader keyboardReader; /** * @param args */ public static void main(String[] args) { try { init(); System.out.println("请在下面输入质数:"); // 获取键盘输入流 keyboardReader = new BufferedReader(new InputStreamReader(System.in)); // 发送数据 send(keyboardReader.readLine()); // 接收响应结果 String result = receive(); // 处理结果 handleResult(result); } catch (IOException e) { e.printStackTrace(); } finally {// 释放资源 StreamUtils.close(buffReader, buffWriter); StreamUtils.close(keyboardReader); close(socket); } } /** * 初始化操作 */ private static void init() { try { // 连接到指定的主机与端口号的服务器上 socket = new Socket(HOST, PORT); InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); buffReader = new BufferedReader(new InputStreamReader(in)); buffWriter = new BufferedWriter(new OutputStreamWriter(out)); } catch (IOException e) { e.printStackTrace(); } } /** * 向服务端发送数据 * @param data */ private static void send(String data) { try { buffWriter.write(data); buffWriter.newLine();// 写一个换行符 buffWriter.flush(); } catch (IOException e) { e.printStackTrace(); } } /** * 接收服务端响应结果 * @return */ private static String receive() { try { return buffReader.readLine(); } catch (IOException e) { e.printStackTrace(); } return null; } /** * 处理服务端返回的结果 */ private static void handleResult(String result) { if ("0".equals(result)) {// 是质数 System.out.println("您输入的是质数"); } else if ("1".equals(result)) {// 不是质数 System.out.println("您输入的不是质数"); } else if ("2".equals(result)) { // 输入非法 System.out.println("警告!您输入非法!"); } } /** * 关闭客户端Socket * @param socket */ private static void close(Socket socket) { if (socket != null) { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } socket = null; } } }
客户端代码分析:
1、获取用户输入的数据,往服务端写数据时,一定要记得用newLine()方法写一个换行符,否则服务端一直处于读取状态,不会停止,因为读不到结束符;同理,服务端在往客户端写入响应结果时,也要用newLine()方法写一个换行符,否则客户端也会一直处于阻塞状态;
2、获取服务端返回的响应结果,根据之前规定的协议,在控制台中输出相应的提示信息。
3)IO流工具类StreamUtils代码:
import java.io.IOException; import java.io.Reader; import java.io.Writer; /** * IO流工具 * @author Sam * */ public class StreamUtils { /** * 同时关闭字符读取流与字符写入流 * @param reader * @param writer */ public static void close(Reader reader, Writer writer) { close(reader); close(writer); } /** * 关闭字符读取流 * @param reader */ public static void close(Reader reader) { if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } reader = null;// 置空 } } /** * 关闭字符写入流 * @param writer */ public static void close(Writer writer) { if (writer != null) { try { writer.close(); } catch (IOException e) { e.printStackTrace(); } writer = null;// 置空 } } }
IO流工具类代码分析:
一般操作中,比较常用的,而且代码变动不大的,我们都会封装成一个工具类,以后直接使用,而不用重复的写。既避免代码冗余,又提高工作效率。
3、运行结果:
注意:先运行Server程序,再运行Client程序。为了测试结果,多次运行Client程序,并输入不同的数据,得到不同的提示信息。
1)Server程序控制台:
2)Client程序控制台
(1)运行第1次:
(2)运行第2次:
(3)运行第3次:
(4)运行第4次:
4、总结:
程序代码的逻辑并不复杂,但是基本做到了代码结构化。每个功能点都封装成一个方法,不同的业务放在不同的代码块中。这样以后要是某个模块出现了问题,就找相应的模块修改,而不被其他逻辑所干扰;实际开始中,也应该是这种思想。
发表评论
-
基于JDK1.6的HashMap底层实现与分析
2018-01-21 14:13 487最新仔细看了一遍JDK1.6 HashMap的源码,收获颇 ... -
Java 中的值传递和引用传递
2016-06-08 20:44 614严格上讲,Java中只存 ... -
Java中的IO流-IO流体系介绍
2014-05-23 17:57 1269工欲善其事,必先利其器。—《论语》 意思是说,工匠要想做好他 ... -
Java中的File类操作
2014-05-22 17:46 1393业精于勤,荒于嬉;行 ... -
Java中的Socket编程(3)-深入
2014-04-16 14:23 696读不在三更五鼓,功只 ... -
Java中的Socket编程(2)-提高
2014-04-11 14:28 854日日行,不怕千万里; ... -
Java中的Socket编程(1)-入门
2014-04-10 14:10 626不积跬步,无以至千里! 意思是说不一小步一小步的积累,无法到 ... -
Java中两种比较器的实现
2014-04-08 15:40 3101先举例说明: 例一:如果要对一组数字进行排序,可以写一个排序 ... -
Java排序算法实现
2014-04-04 17:20 851温故而知新,可以为师矣! 经常温故旧的知识,每次都有新的体会 ...
相关推荐
java大学教程源码中关于socket编程的三个实例
java socket 编程,Java socket 编程实例,对于初学者是一个非常好的东西,对于有过经验的是非常好的更深了解的东西,希望大家共同进步
Java socket编程实例.pdf
Java网络编程案例--CS模型的简单实现
java socket 实现简单的客户端和服务端通信
java socket网络编程,包括服务与客户端,多线程支持多客户端同时在线。
java socket编程实例,各种实例打包
Java Socket 网络编程大全--用实例的方式详细地讲解了java socket网络编程的内容,很全
android socket 编程实例 客户端是android应用程序, socket服务器端使用java作为服务器
用JAVA实现的文件上传,控制台输入,保存到数据库
Java socket编程实例代码,文章讲解可以参考我的blog
Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...
一个用Socket和ServerSocket请求资源的例子
网络组建与实施、SOCKET编程(包括MFC SOCKET编程和JAVA SOCKET编程)等编程实例
主要介绍了Java Socket编程心跳包创建实例解析,具有一定借鉴价值,需要的朋友可以参考下
java Socket编程实例 包括客户端代码和服务器端代码。
Java Socket网络编程实例.pdf 学习资料 复习资料 教学资源
一个Socket实例代表了TCP连接的一个客户端,而一个ServerSocket实例代表了TCP连接的一个服务器端,一般在TCP Socket编程中,客户端有多个,而服务器端只有一个,客户端TCP向服务器端TCP发送连接请求,服务器端的...
java Udp 收发结构体实例 Socket编程 Udp收发大数据 单向传输 无需握手 广播 指定ip
网络通信协议,网络通信基础知识,socket网络编程的一些基础知识,Socket网络编程学习笔记,网络编程总结,2011-学习资料大全:java_socket编程,学习网络编程的十个步骤,socket编程入门(经典版),Unix_网络编程...