20172329 2017-2018-2 《程序设计与数据结构》实验五报告
這是這學期最后一次實驗了,也是學到了很多東西,希望自己可以可以善始善終,加油! 讓我們開始這一篇博客吧!
20172329 2017-2018-2 《程序設計與數據結構》實驗五報告
課程:《程序設計與數據結構》
班級: 1723
姓名: 王文彬
學號:20172329
實驗教師:王志強
實驗日期:2018年6月11日
必修/選修: 必修
一.實驗內容
1、網絡編程與安全-1
- 兩人一組結對編程:
- a. 參考http://www.cnblogs.com/rocedu/p/6766748.html#SECDSA
- b. 結對實現中綴表達式轉后綴表達式的功能 MyBC.java
- c. 結對實現從上面功能中獲取的表達式中實現后綴表達式求值的功能,調用MyDC.java
- d. 上傳測試代碼運行結果截圖和碼云鏈接
2、網絡編程與安全-2
- 結對編程:1人負責客戶端,一人負責服務器
- a. 注意責任歸宿,要會通過測試證明自己沒有問題
- b. 基于Java Socket實現客戶端/服務器功能,傳輸方式用TCP
- c. 客戶端讓用戶輸入中綴表達式,然后把中綴表達式調用MyBC.java的功能轉化為后綴表達式,把后綴表達式通過網絡發送給服務器
- d. 服務器接收到后綴表達式,調用MyDC.java的功能計算后綴表達式的值,把結果發送給客戶端
- e. 客戶端顯示服務器發送過來的結果
- f. 上傳測試結果截圖和碼云鏈接
3、網絡編程與安全-3
- 加密結對編程:1人負責客戶端,一人負責服務器
- a. 注意責任歸宿,要會通過測試證明自己沒有問題
- b. 基于Java Socket實現客戶端/服務器功能,傳輸方式用TCP
- c. 客戶端讓用戶輸入中綴表達式,然后把中綴表達式調用MyBC.java的功能轉化為后綴表達式,把后綴表達式用3DES或AES算法加密后通過網絡把密文發送給服務器
- d. 服務器接收到后綴表達式表達式后,進行解密(和客戶端協商密鑰,可以用數組保存),然后調用MyDC.java的功能計算后綴表達式的值,把結果發送給客戶端
- e. 客戶端顯示服務器發送過來的結果
- f. 上傳測試結果截圖和碼云鏈接
4、網絡編程與安全-4
- 密鑰分發結對編程:1人負責客戶端,一人負責服務器
- a. 注意責任歸宿,要會通過測試證明自己沒有問題
- b. 基于Java Socket實現客戶端/服務器功能,傳輸方式用TCP
- c. 客戶端讓用戶輸入中綴表達式,然后把中綴表達式調用MyBC.java的功能轉化為后綴表達式,把后綴表達式用3DES或AES算法加密通過網絡把密文發送給服務器
- d. 客戶端和服務器用DH算法進行3DES或AES算法的密鑰交換
- e. 服務器接收到后綴表達式表達式后,進行解密,然后調用MyDC.java的功能計算后綴表達式的值,把結果發送給客戶端
- f. 客戶端顯示服務器發送過來的結果
- g. 上傳測試結果截圖和碼云鏈接
5、網絡編程與安全-5
- 完整性校驗結對編程:1人負責客戶端,一人負責服務器
- a. 注意責任歸宿,要會通過測試證明自己沒有問題
- b. 基于Java Socket實現客戶端/服務器功能,傳輸方式用TCP
- c. 客戶端讓用戶輸入中綴表達式,然后把中綴表達式調用MyBC.java的功能轉化為后綴表達式,把后綴表達式用3DES或AES算法加密通過網絡把密文和明文的MD5値發送給服務器
- d. 客戶端和服務器用DH算法進行3DES或AES算法的密鑰交換
- e. 服務器接收到后綴表達式表達式后,進行解密,解密后計算明文的MD5值,和客戶端傳來的MD5進行比較,一致則調用MyDC.java的功能計算后綴表達式的值,把結果發送給客戶端
- f. 客戶端顯示服務器發送過來的結果
- g. 上傳測試結果截圖和碼云鏈接
二. 實驗過程及結果
1、網絡編程與安全-1
- (1)首先我們進行對于題目的閱讀,是讓我們實現之前已經實現的四則運算里面的轉后綴式以及計算一個后綴式的值,雖然在婁老師的博客里面給了兩個方法進行對于一個中綴表達式轉化成一個后綴表達式,但是因為當我們復制粘貼以后發現有一些代碼需要我們去自己寫的時候,就去選擇了自己之前已經寫好的代碼進行對于實驗目標的實現。PS:后期對于婁老師代碼的理解后,發現婁老師的博客和我們的差異不是很大,而且自己的代碼已經寫好了,所以,就沒有再做更換。
- (2)現在就來說一下具體實現的過程,雖然在之前的四則運算的結對編程里面有所體現,但是在這里還是再做敘述。
- first:這一步是將一個中綴轉后綴的一個過程代碼
- second:這一步是將一個后綴式計算出的代碼
結果:
- third:最后將其進行計算結果以及中綴轉后綴的測試
2、網絡編程與安全-2
- (1)首先因為是第一次學習并且運用Java Socket實現客戶端/服務器功能,傳輸方式用TCP進行實驗,因此一開始老師給我們兩個客戶端和服務器的代碼示例,這一個實驗說是進行代碼編寫不如說是進行代碼的補充和修改。首先這一個實驗任務就是先構建一個服務器和客戶端的連接,然后客戶端將一個已經轉為后綴式的中綴表達式傳給服務器,然后服務器接收到這個中綴表達式,進行計算,通過網絡編程與安全-1的實驗代碼進行計算的實現。
- (2)接下來具體來講一講實驗的實現:
一、客戶端
- first:通過這樣一段代碼,將建立與服務器的連接
//1.建立客戶端Socket連接,指定服務器位置和端口Socket socket = new Socket("127.0.0.1",8880);//2.得到socket讀寫流OutputStream outputStream = socket.getOutputStream();OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);//輸入流InputStream inputStream = socket.getInputStream();BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"UTF-8")); - second:通過一系列中綴表達式轉為后綴表達式
//3.利用流按照一定的操作,對socket進行讀寫操作Scanner scan = new Scanner(System.in);System.out.println("我輸入的中綴表達式為: ");String a =scan.nextLine();Calculate p =new Calculate();String temp = "";for (int x = 0; x < p.parse(p.zb(a)).size(); ++x) {temp = temp + p.parse(p.zb(a)).get(x);}String info1 = temp;String info = new String(info1.getBytes("GBK"),"utf-8");outputStreamWriter.write(info);outputStreamWriter.flush();socket.shutdownOutput(); - third:接受到服務器的信息
//接收服務器的響應String reply = null;while (!((reply = bufferedReader.readLine()) ==null)){System.out.println("接收服務器的信息為:" + reply);} 二、服務器
- first:這一步將建立一個服務器,并且準備接受來自客戶端的信息
//1.建立一個服務器Socket(ServerSocket)綁定指定端口ServerSocket serverSocket=new ServerSocket(8880);//2.使用accept()方法阻止等待監聽,獲得新連接Socket socket=serverSocket.accept();//3.獲得輸入流InputStream inputStream=socket.getInputStream();BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));//獲得輸出流OutputStream outputStream=socket.getOutputStream();PrintWriter printWriter=new PrintWriter(outputStream);//4.讀取用戶輸入信息String info=null;while(!((info = bufferedReader.readLine()) ==null)){System.out.println("我是服務器,用戶信息為:" + info); - second:接下來開始對于接受到的信息進行處理,也就是要開始對于接收到的后綴表達式要開始計算,并且將計算出的答案傳給客戶端
//給客戶一個響應Calculate a = new Calculate();String str=info;String[] temp = str.split(" ");List<String> ls= Arrays.asList(temp);String reply=String.valueOf(a.suanshu(ls));printWriter.write(reply);printWriter.flush();} 結果:
- 客戶端:
- 服務器:
3、網絡編程與安全-3
- (1)在這一個實驗中,我們需要用到之前已經學習過的Java與密碼學的練習那一個實驗的相關知識,首先我們需要去溫習一下加密算法有哪些類型,在之前我們了解過的有這樣幾種:3DES、AES、RSA、凱撒密碼,MD5以及一個DH密鑰交換協議的學習,在接下來的實驗中,我們要依次運用到以上的相關知識。這次試驗的目的是客戶端需要將一個已經形成好的后綴表達式進行加密,然后傳遞給服務器將其進行解密,然后將解出來的后綴式進行計算。
- (2)具體來講:
客戶端:
- first:利用這兩個類進行生成密鑰
public class Skey_DES{public static void main(String args[])throws Exception{KeyGenerator kg=KeyGenerator.getInstance("DESede");kg.init(168);SecretKey k=kg.generateKey( );FileOutputStream f=new FileOutputStream("key1.dat");ObjectOutputStream b=new ObjectOutputStream(f);b.writeObject(k);}
} public class Skey_kb{public static void main(String args[]) throws Exception{FileInputStream f=new FileInputStream("key1.dat");ObjectInputStream b=new ObjectInputStream(f);Key k=(Key)b.readObject( );byte[ ] kb=k.getEncoded( );FileOutputStream f2=new FileOutputStream("keykb1.dat");f2.write(kb);// 打印密鑰編碼中的內容for(int i=0;i<kb.length;i++){System.out.print(kb[i]+",");}}
} - second:進行加密
FileInputStream f=new FileInputStream("key1.dat");ObjectInputStream b=new ObjectInputStream(f);Key k=(Key)b.readObject( );Cipher cp=Cipher.getInstance("DESede");cp.init(Cipher.ENCRYPT_MODE, k);byte ptext[]=s.getBytes("UTF8");for(int i=0;i<ptext.length;i++){System.out.print(ptext[i]+",");}System.out.println("");byte ctext[]=cp.doFinal(ptext);String a="";for(int i=0;i<ctext.length;i++){a+=ctext[i] +",";// System.out.print(a);}FileOutputStream f2=new FileOutputStream("SEnc.dat");f2.write(ctext);return a; 服務器:
- third:進行解密
FileInputStream f2=new FileInputStream("keykb1.dat");int num2=f2.available();byte[ ] keykb=new byte[num2];f2.read(keykb);SecretKeySpec k=new SecretKeySpec(keykb,"DESede");// 解密Cipher cp=Cipher.getInstance("DESede");cp.init(Cipher.DECRYPT_MODE, k);byte []ptext=cp.doFinal(ctext);// 顯示明文String p=new String(ptext,"UTF8"); 結果:
- 客戶端:
- 服務器:
4、網絡編程與安全-4
- (1)這一部分的實驗要求我們需要生成新的密鑰從而進行加密和解密的過程,而這個產生新密鑰的過程就是需要用到我們之前學到的DH交換密鑰協議,這里先說一下我對于DH算法的理解:
- 首先,就雙方而言,我們需要去傳遞我們想要的密文就需要一個密鑰,但是我們想要加強安全性,因此就產生了DH算法,它的流程是這樣的:A方會產生一個公鑰和私鑰,這里我們簡稱為公A和私A,B方會產生一個公鑰和一個私鑰,這里簡稱為公B和私B,我們需要交換的是兩個公鑰,從而可以利用我們自己的公鑰和對方的私鑰產生一個新的密鑰,這個密鑰就是我們需要的共享密鑰,我們需要用這個密鑰進行對于明文的加密和解密。
可以結合這個圖進行理解 - (2)具體分析:
- first:進行新密鑰的生成,進行從"Bpub.dat","Apri.dat"讀取文檔,從而生成共享信息,然后進行加密
客戶端:
FileInputStream f1=new FileInputStream("Bpub.dat");ObjectInputStream b1=new ObjectInputStream(f1);PublicKey pbk=(PublicKey)b1.readObject( );
//讀取自己的DH私鑰FileInputStream f3=new FileInputStream("Apri.dat");ObjectInputStream b2=new ObjectInputStream(f3);PrivateKey prk=(PrivateKey)b2.readObject();// 執行密鑰協定KeyAgreement ka=KeyAgreement.getInstance("DH");ka.init(prk);ka.doPhase(pbk,true);//生成共享信息byte[ ] sb=ka.generateSecret();SecretKeySpec k = new SecretKeySpec(sb, 0,24,"DESede");Cipher cp=Cipher.getInstance("DESede");cp.init(Cipher.ENCRYPT_MODE, k);byte ptext[]=s.getBytes("UTF8");byte ctext[]=cp.doFinal(ptext);String a="";for(int i=0;i<ctext.length;i++){a+=ctext[i] +",";// System.out.print(a);}FileOutputStream f2=new FileOutputStream("SEnc.dat");f2.write(ctext);return a; - second:進行解密
服務器:
FileInputStream f1=new FileInputStream("Apub.dat");ObjectInputStream b1=new ObjectInputStream(f1);PublicKey pbk=(PublicKey)b1.readObject( );
//讀取自己的DH私鑰FileInputStream f2=new FileInputStream("Bpri.dat");ObjectInputStream b2=new ObjectInputStream(f2);PrivateKey prk=(PrivateKey)b2.readObject( );// 執行密鑰協定KeyAgreement ka=KeyAgreement.getInstance("DH");ka.init(prk);ka.doPhase(pbk,true);//生成共享信息byte[ ] sb=ka.generateSecret();SecretKeySpec k=new SecretKeySpec(sb,0,24,"DESede");// 解密Cipher cp=Cipher.getInstance("DESede");cp.init(Cipher.DECRYPT_MODE, k);byte []ptext=cp.doFinal(ctext);// 顯示明文String p=new String(ptext,"UTF8");// System.out.println(p); 結果:
5、網絡編程與安全-5
- (1)第五個實驗是關于MD5關于Java的摘要算法
- (2)具體實現:
- first:計算明文的MD5值
public String Diget(String x) throws UnsupportedEncodingException, NoSuchAlgorithmException {MessageDigest m=MessageDigest.getInstance("MD5");m.update(x.getBytes("UTF8"));byte s[ ]=m.digest( );String result="";for (int i=0; i<s.length; i++){result+=Integer.toHexString((0x000000ff & s[i]) |0xffffff00).substring(6);}return result;} - second:進行對比,如果一樣,則計算,不一樣則拋出異常
DigestPass ooo=new DigestPass();String reply;if (ww.equals(ooo.Diget(p))){reply= String.valueOf(a.suanshu(ls));}else {reply="返回的MD5值不同";} 結果:
- 客戶端:
- 服務器:
三. 實驗過程中遇到的問題和解決過程
- 問題1:在做第三個實驗的時候,就到底如何傳給服務器密鑰大家產生了很大的分歧,很多人認為需要用像是傳遞原文的方式進行,有些人認為應該用文件直接拷貝過去就可以
- 問題1解答:我認為兩種方式都可以。
- 首先我們先分析第一種方法,也就是通過傳遞原文的方式將其傳遞過去,但是這里就會有問題,因為,我們不清楚到底是如何去傳遞兩個東西,我們并沒有被要求去用雙線程,況且我們也沒有那么厲害,因此通過和余坤澎同學的討論,我們可以用這個方法進行將兩個東西傳遞過去,舉個例子:假如我們現在要傳遞字符串A和字符串B,但是我們怎么把兩個東西一起傳遞過去呢,首先我們想到,就字符串有一個
split的方法,我們可以利用這個方法把這兩個字符串用一個字符進行切分,然后分別保存,比如“String aa =A;B”,我們用String []bb =aa.split";";就可以將其分成bb[0]和bb[1]這樣就把兩個東西都傳遞過去了。 其次就是第二種方式,我相信第二種方式不用太過去強調,我認為是個人應該都會的,而且最開始想到的辦法肯定也是這一種方法。
- 問題2:在服務器接受到的info總是空指針這問題
問題2解決方案:
String info=null;String str1="";while(!((info = bufferedReader.readLine()) ==null)){System.out.println("我是服務器,用戶信息為:" + info);str1=info;} String info=null;while(!((info = bufferedReader.readLine()) ==null)){System.out.println("我是服務器,用戶信息為:" + info);}
我們需要區分這兩個代碼的區別,運用第二個會出現報錯,出現空指針,因為第二個代碼的info是直到它為空才會跳出這個循環,自然會拋出空指針的異常。
- 問題3:在做到第四個實驗的時候,有一個問題卡了我很久,就是密鑰長度的問題
- 問題3解決方案:
- 因為一開始我查了為什么是這個問題,就是因為生成的密鑰長度不符合3DES的要求,因此就會導致這個問題,我們知道3DES的密鑰長度要求是8的倍數,并且在我們這個實驗里DESede需要的是24位,但是我們得到的共享密鑰是128位的所以它會冒出密鑰長度的問題,在這里先感謝張旭升學長對我的幫助,解決方法就在這一句
SecretKeySpec k =new SecretKeySpec(sb,"DESede");可以實現,首先我們的目的是想要把那個128的密鑰只取24位,因此我們查找了API文檔
看了看這句話的參數有什么,其中就有控制范圍:
將語句變成SecretKeySpec k=new SecretKeySpec(sb,0,24,"DESede");,問題也就可以解決了。
其他(感悟、思考等)
這一學期馬上就要結束了,很多人現在也都已經開始放飛自我了,端午這三天,自己決定自己的收獲還是非常大的,最近的幾次編程,我覺得我學習Java的熱情又回來了,然后我發現API真是個好東西,就像一本字典一樣,而且講解的都非常詳細,希望自己可以堅持下去,自己立的flag,一定要做到!
參考資料
藍墨云班課
2016-2017-2 《Java 程序設計》課堂實踐項目
Java 密碼學算法
JAVA加解密DH算法
3DES自定義密鑰問題
JAVA實現DES加密實現詳解
多線程方式實現Socket通信
TCP
轉載于:https://www.cnblogs.com/qh45wangwenbin/p/9193738.html
總結
以上是生活随笔為你收集整理的20172329 2017-2018-2 《程序设计与数据结构》实验五报告的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 办理房产证土地证需要交纳多少费用
- 下一篇: 一篇文章让你读懂Pivotal的GemF