精选 java 等全套视频教程
精选 java 电子图书
大数据视频教程精选
java 项目练习精选
猜数字小游戏
下面这个示例是一个猜数字的控制台小游戏该游戏的规则是: 当客户端第一次连接到服务器端时, 服务器端生产一个 0,50 之间的随机数字, 然后客户端输入数字来猜该数字, 每次客户端输入数字以后, 发送给服务器端, 服务器端判断该客户端发送的数字和随机数字的关系, 并反馈比较结果, 客户端总共有 5 次猜的机会, 猜中时提示猜中, 当输入 quit 时结束程序
和前面的示例类似, 在进行网络程序开发时, 首先需要分解一下功能的实现, 觉得功能是在客户端程序中实现还是在服务器端程序中实现区分的规则一般是: 客户端 程序实现接收用户输入等界面功能, 并实现一些基础的校验降低服务器端的压力, 而将程序核心的逻辑以及数据存储等功能放在服务器端进行实现遵循该原则划分 的客户端和服务器端功能如下所示
客户端程序功能列表:
接收用户控制台输入
判断输入内容是否合法
按照协议格式发送数据
根据服务器端的反馈给出相应提示
服务器端程序功能列表:
接收客户端发送数据
按照协议格式解析数据
判断发送过来的数字和随机数字的关系
根据判断结果生产协议数据
将生产的数据反馈给客户端
在该示例中, 实际使用的网络命令也只有两条, 所以显得协议的格式比较简单
其中客户端程序协议格式如下:
将用户输入的数字转换为字符串, 然后转换为 byte 数组
发送 quit 字符串代表退出
其中服务器端程序协议格式如下:
反馈长度为 1 个字节, 数字 0 代表相等(猜中),1 代表大了, 2 代表小了, 其它数字代表错误
实现该程序的代码比较多, 下面分为客户端程序实现和服务器端程序实现分别进行列举
客户端程序实现代码如下:
- package guess;
- import java.net.*;
- import java.io.*;
- /**
- * 猜数字客户端
- */
- public class TCPClient {
- public static void main(String[] args) {
- Socket socket = null;
- OutputStream os = null;
- InputStream is = null;
- BufferedReader br = null;
- byte[] data = new byte[2];
- try{
- // 建立连接
- socket = new Socket(
- "127.0.0.1",10001);
- // 发送数据
- os= socket.getOutputStream();
- // 读取反馈数据
- is = socket.getInputStream();
- // 键盘输入流
- br = new BufferedReader(
- new InputStreamReader(System.in));
- // 多次输入
- while(true){
- System.out.println("请输入数字:");
- // 接收输入
- String s = br.readLine();
- // 结束条件
- if(s.equals("quit")){
- os.write("quit".getBytes());
- break;
- }
- // 校验输入是否合法
- boolean b = true;
- try{
- Integer.parseInt(s);
- }catch(Exception e){
- b = false;
- }
- if(b){ // 输入合法
- // 发送数据
- os.write(s.getBytes());
- // 接收反馈
- is.read(data);
- // 判断
- switch(data[0]){
- case 0:
- System.out.println("相等! 祝贺你!");
- break;
- case 1:
- System.out.println("大了!");
- break;
- case 2:
- System.out.println("小了!");
- break;
- default:
- System.out.println("其它错误!");
- }
- // 提示猜的次数
- System.out.println("你已经猜了" + data[1] + "次!");
- // 判断次数是否达到 5 次
- if(data[1] >= 5){
- System.out.println("你挂了!");
- // 给服务器端线程关闭的机会
- os.write("quit".getBytes());
- // 结束客户端程序
- break;
- }
- }else{ // 输入错误
- System.out.println("输入错误!");
- }
- }
- }catch(Exception e){
- e.printStackTrace();
- }finally{
- try{
- // 关闭连接
- br.close();
- is.close();
- os.close();
- socket.close();
- }catch(Exception e){
- e.printStackTrace();
- }
- }
- }
- }
在该示例中, 首先建立一个到 IP 地址为 127.0.0.1 的端口为 10001 的连接, 然后进行各个流的初始化工作, 将逻辑控制的代码放入在一个 while 循环中, 这样可以在客户端多次进行输入在循环内部, 首先判断用户输入的是否为 quit 字符串, 如果是则结束程序, 如果输入不是 quit, 则首先校验输入的是否是数字, 如果不是数字则直接输出输入错误! 并继续接收用户输入, 如果是数字则发送给服务器端, 并根据服务器端的反馈显示相应的提示信息最后关闭流和连接, 结束客户端程序
服务器端程序的实现还是分为服务器控制程序和逻辑线程, 实现的代码分别如下:
- package guess;
- import java.net.*;
- /**
- * TCP 连接方式的服务器端
- * 实现功能: 接收客户端的数据, 判断数字关系
- */
- public class TCPServer {
- public static void main(String[] args) {
- try{
- // 监听端口
- ServerSocket ss = new ServerSocket(10001);
- System.out.println("服务器已启动:");
- // 逻辑处理
- while(true){
- // 获得连接
- Socket s = ss.accept();
- // 启动线程处理
- new LogicThread(s);
- }
- }catch(Exception e){
- e.printStackTrace();
- }
- }
- }
- package guess;
- import java.net.*;
- import java.io.*;
- import java.util.*;
- /**
- * 逻辑处理线程
- */
- public class LogicThread extends Thread {
- Socket s;
- static Random r = new Random();
- public LogicThread(Socket s){
- this.s = s;
- start(); // 启动线程
- }
- public void run(){
- // 生成一个 [0,50] 的随机数
- int randomNumber = Math.abs(r.nextInt() % 51);
- // 用户猜的次数
- int guessNumber = 0;
- InputStream is = null;
- OutputStream os = null;
- byte[] data = new byte[2];
- try{
- // 获得输入流
- is = s.getInputStream();
- // 获得输出流
- os = s.getOutputStream();
- while(true){ // 多次处理
- // 读取客户端发送的数据
- byte[] b = new byte[1024];
- int n = is.read(b);
- String send = new String(b,0,n);
- // 结束判别
- if(send.equals("quit")){
- break;
- }
- // 解析判断
- try{
- int num = Integer.parseInt(send);
- // 处理
- guessNumber++; // 猜的次数增加 1
- data[1] = (byte)guessNumber;
- // 判断
- if(num > randomNumber){
- data[0] = 1;
- }else if(num < randomNumber){
- data[0] = 2;
- }else{
- data[0] = 0;
- // 如果猜对
- guessNumber = 0; // 清零
- randomNumber = Math.abs(r.nextInt() % 51);
- }
- // 反馈给客户端
- os.write(data);
- }catch(Exception e){ // 数据格式错误
- data[0] = 3;
- data[1] = (byte)guessNumber;
- os.write(data); // 发送错误标识
- break;
- }
- os.flush(); // 强制发送
- }
- }catch(Exception e){
- e.printStackTrace();
- }finally{
- try{
- is.close();
- os.close();
- s.close();
- }catch(Exception e){}
- }
- }
- }
在 该示例中, 服务器端控制部分和前面的示例中一样也是等待客户端连接, 如果有客户端连接到达时, 则启动新的线程去处理客户端连接在逻辑线程中实现程序的 核心逻辑, 首先当线程执行时生产一个随机数字, 然后根据客户端发送过来的数据, 判断客户端发送数字和随机数字的关系, 然后反馈相应的数字的值, 并记忆客户 端已经猜过的次数, 当客户端猜中以后清零猜过的次数, 使得客户端程序可以继续进行游戏
总体来说, 该程序示例的结构以及功能都与上一个程序比较类似, 希望通过比较这两个程序, 加深对于网络编程的认识, 早日步入网络编程的大门
来源: http://mp.weixin.qq.com/s/4QEbxzOjBMJXfDog4cXMOQ