## Java編程那些事兒109——網絡編程示例2
陳躍峰
出自:[http://blog.csdn.net/mailbomb](http://blog.csdn.net/mailbomb)
**13.3.2 猜數字小游戲**
下面這個示例是一個猜數字的控制臺小游戲。該游戲的規則是:當客戶端第一次連接到服務器端時,服務器端生產一個【0,50】之間的隨機數字,然后客戶端輸入數字來猜該數字,每次客戶端輸入數字以后,發送給服務器端,服務器端判斷該客戶端發送的數字和隨機數字的關系,并反饋比較結果,客戶端總共有5次猜的機會,猜中時提示猜中,當輸入”quit”時結束程序。
和前面的示例類似,在進行網絡程序開發時,首先需要分解一下功能的實現,覺得功能是在客戶端程序中實現還是在服務器端程序中實現。區分的規則一般是:客戶端程序實現接收用戶輸入等界面功能,并實現一些基礎的校驗降低服務器端的壓力,而將程序核心的邏輯以及數據存儲等功能放在服務器端進行實現。遵循該原則劃分的客戶端和服務器端功能如下所示。
客戶端程序功能列表:
1、? 接收用戶控制臺輸入
2、? 判斷輸入內容是否合法
3、? 按照協議格式發送數據
4、? 根據服務器端的反饋給出相應提示
服務器端程序功能列表:
1、? 接收客戶端發送數據
2、? 按照協議格式解析數據
3、? 判斷發送過來的數字和隨機數字的關系
4、? 根據判斷結果生產協議數據
5、? 將生產的數據反饋給客戶端
在該示例中,實際使用的網絡命令也只有兩條,所以顯得協議的格式比較簡單。
其中客戶端程序協議格式如下:
1、? 將用戶輸入的數字轉換為字符串,然后轉換為byte數組
2、? 發送“quit”字符串代表退出
其中服務器端程序協議格式如下:
1、? 反饋長度為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){}
????????????? }
????? }
}
~~~
在該示例中,服務器端控制部分和前面的示例中一樣。也是等待客戶端連接,如果有客戶端連接到達時,則啟動新的線程去處理客戶端連接。在邏輯線程中實現程序的核心邏輯,首先當線程執行時生產一個隨機數字,然后根據客戶端發送過來的數據,判斷客戶端發送數字和隨機數字的關系,然后反饋相應的數字的值,并記憶客戶端已經猜過的次數,當客戶端猜中以后清零猜過的次數,使得客戶端程序可以繼續進行游戲。
總體來說,該程序示例的結構以及功能都與上一個程序比較類似,希望通過比較這兩個程序,加深對于網絡編程的認識,早日步入網絡編程的大門。
- 前言
- (1)序言
- (2)程序設計是什么?
- (3)你適合學習程序設計嗎?
- (4)如何學好程序設計?
- (5)程序設計介紹小結
- (6)計算機軟件基本概念
- (7)進制的概念
- (8)計算機內部的數據表達
- (9)網絡編程基礎
- (10)Java語言簡介
- (11)JDK的獲得、安裝和配置
- (12)第一個HelloWorld程序
- (13)Eclipse基本使用
- (14)Eclipse基礎使用進階
- (15)如何學好Java語法
- (16)代碼框架、關鍵字和標識符
- (17)基本數據類型
- (18)變量和常量
- (19)數據類型轉換
- (20)空白、語句結束和注釋
- (21)算術運算符
- (22)比較運算符
- (23)邏輯運算符
- (24)賦值運算符
- (25)位運算符
- (26)移位運算符
- (27)其它運算符
- (28)運算符優先級
- (29)表達式
- (30)流程控制基礎
- (31)if語句語法(1)
- (32)if語句語法(2)
- (33)if語句語法(3)
- (34)switch語句語法
- (35)while語句語法
- (36)do-while語句語法
- (37)for語句語法
- (38)break和continue語句
- (39)流程控制綜合示例1
- (40)流程控制綜合示例2
- (41)流程控制綜合示例3
- (42)流程控制綜合練習
- (43)數組概述
- (44)數組基礎語法
- (45)數組使用示例1
- (46)數組使用示例2
- (47)數組使用示例3
- (48)多維數組基礎
- (49)多維數組使用示例1
- (50)多維數組使用示例2
- (51)多維數組練習
- (52)方法聲明
- (53)方法聲明示例
- (54)方法調用
- (55)方法重載和參數傳遞
- (56)方法練習
- (57)面向對象基礎
- (58)類(一)
- (59)類(二)
- (60)對象
- (61)面向對象設計方法和面向對象特性(一)
- (62)繼承(二)
- (63)多態性
- (64)訪問控制符、修飾符和其它關鍵字
- (65)static修飾符
- (66)final修飾符
- (67)this和super
- (68)抽象類和接口(一)
- (69)抽象類和接口(二)
- (70)抽象類和接口(三)
- (71)內部類簡介
- (72)包的概念
- (73)JDK文檔使用
- (74)java.lang包介紹1
- (75)String類使用
- (76)StringBuffer類和System類
- (77)包裝類
- (78)時間和日期處理
- (79)Random隨機處理
- (80)集合框架簡述
- (81)異常處理概述
- (82)異常處理語法1
- (83)異常處理語法2
- (84)IO簡介
- (85)IO類體系
- (86)文件操作之File類使用
- (87)文件操作之讀取文件
- (88)文件操作之寫文件
- (89)讀取控制臺輸入
- (90)裝飾流使用1
- (91)裝飾流使用2
- (92)IO使用注意問題
- (93)多線程基礎
- (94)多線程實現方式1
- (95)多線程實現方式2
- (96)多線程使用示例1
- (97)多線程使用示例2
- (98)多線程問題及處理1
- (99)多線程問題及處理2
- (100)多線程問題及處理3
- (101)網絡編程概述
- (102)網絡編程技術1
- (103)網絡編程技術2
- (104)網絡編程技術3
- (105)網絡編程技術4
- (106)網絡編程技術5
- (107)網絡協議概念
- (108)網絡編程示例1
- (109)網絡編程示例2
- (110)網絡編程小結