課程:Java程序設計 班級:1652班 姓名:王高源 學號:20165225 指導教師:婁嘉鵬 實驗日期:2018年5月14日 實驗時間:3:35 - 5:15 實驗序號:實驗5 實驗名稱:網絡編程與安全 實驗內容: 一、掌握Java Socket的相關內容; 二、學會創建客戶端與服務器端之間的聯繫; 三、學習並應用密碼學的相關內容 嚴禁抄襲,有該行爲者實驗成績歸零,並附加其餘懲罰措施。
實驗要求:html
兩人一組結對編程:java
參考http://www.cnblogs.com/rocedu/p/6766748.html#SECDSA
結對實現中綴表達式轉後綴表達式的功能 MyBC.java
結對實現從上面功能中獲取的表達式中實現後綴表達式求值的功能,調用MyDC.java算法
實驗代碼:express
Client編程
import java.net.*; import java.io.*; public class Client { public static void main(String srgs[]) throws Exception { try { // 一、建立客戶端Socket,指定服務器地址和端口 Socket socket=new Socket("127.0.0.1",10000); System.out.println("客戶端成功啓動,等待服務器應答"); // 二、獲取輸出流,向服務器端發送信息 // 向本機的10001端口發出客戶請求 System.out.println("請輸入中綴表達式:"); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 由系統標準輸入設備構造BufferedReader對象 PrintWriter write = new PrintWriter(socket.getOutputStream()); // 由Socket對象獲得輸出流,並構造PrintWriter對象 //三、獲取輸入流,並讀取服務器端的響應信息 BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); // 由Socket對象獲得輸入流,並構造相應的BufferedReader對象 String readline, infix, expression; readline = br.readLine(); // 從系統標準輸入讀入一字符串 MyBC theTrans = new MyBC(readline); infix = theTrans.doTrans(); StringBuilder newInfix = new StringBuilder(infix.replace(" ","")); for (int i = 1; i < infix.length()+(i+1)/2 ; i=i+2) { newInfix.insert(i," "); } System.out.println("後綴表達式:" + newInfix); expression=newInfix.toString(); while (!readline.equals("end")) { // 若從標準輸入讀入的字符串爲 "end"則中止循環 write.println(expression); // 將從系統標準輸入讀入的字符串輸出到Server write.flush(); // 刷新輸出流,使Server立刻收到該字符串 System.out.println("收到服務器的消息:" + in.readLine()); // 從Server讀入一字符串,並打印到標準輸出上 readline = br.readLine(); // 從系統標準輸入讀入一字符串 } // 繼續循環 //四、關閉資源 write.close(); // 關閉Socket輸出流 in.close(); // 關閉Socket輸入流 socket.close(); // 關閉Socket } catch (Exception e) { System.out.println(e);//輸出異常 } finally { } } }
Server數組
import java.net.*; import java.io.*; public class Server{ public static void main(String srgs[]) throws Exception { ServerSocket sc = null; Socket socket=null; try { MyDC evaluator = new MyDC(); sc= new ServerSocket(10000);//建立服務器套接字 System.out.println("端口號:" + sc.getLocalPort()); System.out.println("服務器成功啓動,等待客戶端呼叫"); socket = sc.accept(); //等待客戶端鏈接 System.out.println("已經創建鏈接");//得到網絡輸入流對象的引用 BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));//得到網絡輸出流對象的引用 PrintWriter out=new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true); String aline2=in.readLine(); System.out.println("客戶端發來的信息爲:"+aline2); int ans = evaluator.evaluate(aline2); out.println(ans); System.out.println("result = "+ans); } catch (Exception e) { System.out.println(e); } } //十六進制和十進制轉換 public static byte[] parseHexStr2Byte(String hexStr) { if (hexStr.length() < 1) return null; byte[] result = new byte[hexStr.length()/2]; for (int i = 0;i< hexStr.length()/2; i++) { int high = Integer.parseInt(hexStr.substring(i*2, i*2+1 ), 16); int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16); result[i] = (byte) (high * 16 + low); } return result; } }
MyDc安全
import java.util.StringTokenizer; import java.util.Stack; public class MyDC { /** * constant for addition symbol */ private final char ADD = '+'; /** * constant for subtraction symbol */ private final char SUBTRACT = '-'; /** * constant for multiplication symbol */ private final char MULTIPLY = '*'; /** * constant for division symbol */ private final char DIVIDE = '/'; /** * the stack */ private Stack<Integer> stack; public MyDC() { stack = new Stack<Integer>(); } public int evaluate(String expr) { int op1, op2, result = 0; String token; StringTokenizer tokenizer = new StringTokenizer(expr); while (tokenizer.hasMoreTokens()) { token = tokenizer.nextToken(); //若是是運算符,調用isOperator if (isOperator(token)) { //從棧中彈出操做數2 op2 = stack.pop(); //從棧中彈出操做數1 op1 = stack.pop(); //根據運算符和兩個操做數調用evalSingleOp計算result; result=evalSingleOp(token.charAt(0), op1, op2); //計算result入棧; stack.push(result); } else//若是是操做數 //操做數入棧; stack.push(Integer.parseInt(token)); } return result; } private boolean isOperator(String token) { return (token.equals("+") || token.equals("-") || token.equals("*") || token.equals("/")); } private int evalSingleOp(char operation, int op1, int op2) { int result = 0; switch (operation) { case ADD: result = op1 + op2; break; case SUBTRACT: result = op1 - op2; break; case MULTIPLY: result = op1 * op2; break; case DIVIDE: result = op1 / op2; } return result; } }
MyBc服務器
public class MyBC { private Stack theStack; private String input; private String output = ""; public MyBC(String in) { input = in; int stackSize = input.length(); theStack = new Stack(stackSize); } public String doTrans() { for (int j = 0; j < input.length(); j++) { char ch = input.charAt(j); switch (ch) { case '+': case '-': gotOper(ch, 1); break; case '*': case '/': gotOper(ch, 2); break; case '(': theStack.push(ch); break; case ')': gotParen(ch); break; default: output = output + ch; break; } } while (!theStack.isEmpty()) { output = output + theStack.pop(); } return output; } public void gotOper(char opThis, int prec1) { while (!theStack.isEmpty()) { char opTop = theStack.pop(); if (opTop == '(') { theStack.push(opTop); break; } else { int prec2; if (opTop == '+' || opTop == '-') prec2 = 1; else prec2 = 2; if (prec2 < prec1) { theStack.push(opTop); break; } else output = output + opTop; } } theStack.push(opThis); } public void gotParen(char ch){ while (!theStack.isEmpty()) { char chx = theStack.pop(); if (chx == '(') break; else output = output + chx; } } class Stack { private int maxSize; private char[] stackArray; private int top; public Stack(int max) { maxSize = max; stackArray = new char[maxSize]; top = -1; } public void push(char j) { stackArray[++top] = j; } public char pop() { return stackArray[top--]; } public char peek() { return stackArray[top]; } public boolean isEmpty() { return (top == -1); } } }
實驗截圖:網絡
結對編程:1人負責客戶端,一人負責服務器socket
注意責任歸宿,要會經過測試證實本身沒有問題
基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
客戶端讓用戶輸入中綴表達式,而後把中綴表達式調用MyBC.java的功能轉化爲後綴表達式,把後綴表達式經過網絡發送給服務器
服務器接收到後綴表達式,調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
客戶端顯示服務器發送過來的結果
實驗代碼:
Server
import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class Server1 { public static void main(String args[]) { ServerSocket serverForClient = null; Socket socketOnServer = null; DataOutputStream out = null; DataInputStream in = null; try { serverForClient = new ServerSocket(3001); } catch (IOException e1) { System.out.println(e1); } try { System.out.println("等待客戶呼叫"); socketOnServer = serverForClient.accept(); //堵塞狀態,除非有客戶呼叫 System.out.println("客戶已鏈接"); out = new DataOutputStream(socketOnServer.getOutputStream()); in = new DataInputStream(socketOnServer.getInputStream()); String leng = in.readUTF(); // in讀取信息,堵塞狀態 byte ctext[] = new byte[Integer.parseInt(leng)]; for (int i = 0;i<Integer.parseInt(leng);i++) { String temp = in.readUTF(); ctext[i] = Byte.parseByte(temp); } // 獲取密鑰 FileInputStream f2 = new FileInputStream("keykb1.txt"); 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); System.out.println("後綴表達式已被解密:"); for (int i = 0; i < ptext.length; i++) { System.out.print(ptext[i] + ","); } System.out.println(""); // 顯示明文 String p = new String(ptext, "UTF8"); System.out.println("服務器收到客戶的請求:計算後綴表達式" + p); MyDC evaluator = new MyDC(); out.writeUTF(evaluator.evaluate(p)+""); } catch (Exception e) { System.out.println("客戶已斷開" + e); } } }
Client
實驗截圖:
加密結對編程:1人負責客戶端,一人負責服務器
注意責任歸宿,要會經過測試證實本身沒有問題
基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
客戶端讓用戶輸入中綴表達式,而後把中綴表達式調用MyBC.java的功能轉化爲後綴表達式,把後綴表達式用3DES或AES算法加密後經過網絡把密文發送給服務器
服務器接收到後綴表達式表達式後,進行解密(和客戶端協商密鑰,能夠用數組保存),而後調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
客戶端顯示服務器發送過來的結果
實驗代碼:
Server
import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.security.Key; import java.util.Optional; public class Server2 { public static void main(String args[]) { ServerSocket serverForClient = null; Socket socketOnServer = null; DataOutputStream out = null; DataInputStream in = null; try { serverForClient = new ServerSocket(2010); } catch (IOException e1) { System.out.println(e1); } try { System.out.println("等待客戶呼叫"); socketOnServer = serverForClient.accept(); //堵塞狀態,除非有客戶呼叫 System.out.println("客戶已鏈接"); out = new DataOutputStream(socketOnServer.getOutputStream()); in = new DataInputStream(socketOnServer.getInputStream()); Key_DH.fun("Spub.txt","Spri.txt"); int len = Integer.parseInt(in.readUTF()); byte np[] = new byte[len]; for (int i = 0;i<len;i++) { String temp = in.readUTF(); np[i] = Byte.parseByte(temp); } ObjectInputStream ois = new ObjectInputStream (new ByteArrayInputStream (np)); Key k2 = (Key)ois.readObject();; FileOutputStream f2 = new FileOutputStream("Cpub.txt"); ObjectOutputStream b2 = new ObjectOutputStream(f2); b2.writeObject(k2); FileInputStream fp = new FileInputStream("Spub.txt"); ObjectInputStream bp = new ObjectInputStream(fp); Key kp = (Key) bp.readObject(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(kp); byte[] kb = baos.toByteArray(); out.writeUTF(kb.length + ""); for (int i = 0; i < kb.length; i++) { out.writeUTF(kb[i] + ""); } KeyAgree.fun("Cpub.txt","Spri.txt"); String leng = in.readUTF(); // in讀取信息,堵塞狀態 byte ctext[] = new byte[Integer.parseInt(leng)]; for (int i = 0;i<Integer.parseInt(leng);i++) { String temp = in.readUTF(); ctext[i] = Byte.parseByte(temp); } // 獲取密鑰 FileInputStream f = new FileInputStream("sb.txt"); byte[] keysb = new byte[24]; f.read(keysb); System.out.println("公共密鑰:"); for (int i = 0;i<24;i++) { System.out.print(keysb[i]+","); } System.out.println(""); SecretKeySpec k = new SecretKeySpec(keysb, "DESede"); // 解密 Cipher cp = Cipher.getInstance("DESede"); cp.init(Cipher.DECRYPT_MODE, k); byte[] ptext = cp.doFinal(ctext); System.out.println("後綴表達式已被解密:"); for (int i = 0; i < ptext.length; i++) { System.out.print(ptext[i] + ","); } System.out.println(""); // 顯示明文 String p = new String(ptext, "UTF8"); System.out.println("服務器收到客戶的請求:計算後綴表達式" + p); MyDC evaluator = new MyDC(); out.writeUTF(evaluator.evaluate(p)+""); } catch (Exception e) { System.out.println("客戶已斷開" + e); } } }
實驗編程:
密鑰分發結對編程:1人負責客戶端,一人負責服務器
注意責任歸宿,要會經過測試證實本身沒有問題
基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
客戶端讓用戶輸入中綴表達式,而後把中綴表達式調用MyBC.java的功能轉化爲後綴表達式,把後綴表達式用3DES或AES算法加密經過網絡把密文發送給服務器
客戶端和服務器用DH算法進行3DES或AES算法的密鑰交換
服務器接收到後綴表達式表達式後,進行解密,而後調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
客戶端顯示服務器發送過來的結果
實驗代碼:
server
import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.security.Key; public class Server3 { public static void main(String args[]) { ServerSocket serverForClient = null; Socket socketOnServer = null; DataOutputStream out = null; DataInputStream in = null; try { serverForClient = new ServerSocket(3001); } catch (IOException e1) { System.out.println(e1); } try { System.out.println("等待客戶呼叫"); socketOnServer = serverForClient.accept(); //堵塞狀態,除非有客戶呼叫 System.out.println("客戶已鏈接"); out = new DataOutputStream(socketOnServer.getOutputStream()); in = new DataInputStream(socketOnServer.getInputStream()); Key_DH.fun("Spub.txt","Spri.txt"); int len = Integer.parseInt(in.readUTF()); byte np[] = new byte[len]; for (int i = 0;i<len;i++) { String temp = in.readUTF(); np[i] = Byte.parseByte(temp); } ObjectInputStream ois = new ObjectInputStream (new ByteArrayInputStream(np)); Key k2 = (Key)ois.readObject();; FileOutputStream f2 = new FileOutputStream("Cpub.txt"); ObjectOutputStream b2 = new ObjectOutputStream(f2); b2.writeObject(k2); FileInputStream fp = new FileInputStream("Spub.txt"); ObjectInputStream bp = new ObjectInputStream(fp); Key kp = (Key) bp.readObject(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(kp); byte[] kb = baos.toByteArray(); out.writeUTF(kb.length + ""); for (int i = 0; i < kb.length; i++) { out.writeUTF(kb[i] + ""); } KeyAgree.fun("Cpub.txt","Spri.txt"); String leng = in.readUTF(); // in讀取信息,堵塞狀態 byte ctext[] = new byte[Integer.parseInt(leng)]; for (int i = 0;i<Integer.parseInt(leng);i++) { String temp = in.readUTF(); ctext[i] = Byte.parseByte(temp); } String check = in.readUTF(); // 獲取密鑰 FileInputStream f = new FileInputStream("sb.txt"); byte[] keysb = new byte[24]; f.read(keysb); System.out.println("公共密鑰:"); for (int i = 0;i<24;i++) { System.out.print(keysb[i]+","); } System.out.println(""); SecretKeySpec k = new SecretKeySpec(keysb, "DESede"); // 解密 Cipher cp = Cipher.getInstance("DESede"); cp.init(Cipher.DECRYPT_MODE, k); byte[] ptext = cp.doFinal(ctext); System.out.println("後綴表達式已被解密:"); for (int i = 0; i < ptext.length; i++) { System.out.print(ptext[i] + ","); } System.out.println(""); // 顯示明文 String p = new String(ptext, "UTF8"); String pMd5 = DigestPass.fun(p); System.out.println("解密後明文的MD5值:"+pMd5); if (pMd5.equals(check)){ System.out.println("和客戶端的MD5值一致"); System.out.println("服務器收到客戶的請求:計算後綴表達式" + p); MyDC evaluator = new MyDC(); out.writeUTF(evaluator.evaluate(p)+""); } else { System.out.println("警告:和客戶端的MD5值不一致!"); } } catch (Exception e) { System.out.println("客戶已斷開" + e); } } }
實驗截圖:
完整性校驗結對編程:1人負責客戶端,一人負責服務器
注意責任歸宿,要會經過測試證實本身沒有問題
基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
客戶端讓用戶輸入中綴表達式,而後把中綴表達式調用MyBC.java的功能轉化爲後綴表達式,把後綴表達式用3DES或AES算法加密經過網絡把密文和明文的MD5値發送給服務器
客戶端和服務器用DH算法進行3DES或AES算法的密鑰交換
服務器接收到後綴表達式表達式後,進行解密,解密後計算明文的MD5值,和客戶端傳來的MD5進行比較,一致則調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
客戶端顯示服務器發送過來的結果
實驗代碼:
Client
import java.net.*; import java.io.*; public class Client { public static void main(String srgs[]) throws Exception { try { // 一、建立客戶端Socket,指定服務器地址和端口 Socket socket=new Socket("127.0.0.1",10000); System.out.println("客戶端成功啓動,等待服務器應答"); // 二、獲取輸出流,向服務器端發送信息 // 向本機的10001端口發出客戶請求 System.out.println("請輸入中綴表達式:"); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 由系統標準輸入設備構造BufferedReader對象 PrintWriter write = new PrintWriter(socket.getOutputStream()); // 由Socket對象獲得輸出流,並構造PrintWriter對象 //三、獲取輸入流,並讀取服務器端的響應信息 BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); // 由Socket對象獲得輸入流,並構造相應的BufferedReader對象 String readline, infix, expression; readline = br.readLine(); // 從系統標準輸入讀入一字符串 MyBC theTrans = new MyBC(readline); infix = theTrans.doTrans(); StringBuilder newInfix = new StringBuilder(infix.replace(" ","")); for (int i = 1; i < infix.length()+(i+1)/2 ; i=i+2) { newInfix.insert(i," "); } System.out.println("後綴表達式:" + newInfix); expression=newInfix.toString(); while (!readline.equals("end")) { // 若從標準輸入讀入的字符串爲 "end"則中止循環 write.println(expression); // 將從系統標準輸入讀入的字符串輸出到Server write.flush(); // 刷新輸出流,使Server立刻收到該字符串 System.out.println("收到服務器的消息:" + in.readLine()); // 從Server讀入一字符串,並打印到標準輸出上 readline = br.readLine(); // 從系統標準輸入讀入一字符串 } // 繼續循環 //四、關閉資源 write.close(); // 關閉Socket輸出流 in.close(); // 關閉Socket輸入流 socket.close(); // 關閉Socket } catch (Exception e) { System.out.println(e);//輸出異常 } finally { } } }import java.net.*; import java.io.*; public class Client { public static void main(String srgs[]) throws Exception { try { // 一、建立客戶端Socket,指定服務器地址和端口 Socket socket=new Socket("127.0.0.1",10000); System.out.println("客戶端成功啓動,等待服務器應答"); // 二、獲取輸出流,向服務器端發送信息 // 向本機的10001端口發出客戶請求 System.out.println("請輸入中綴表達式:"); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 由系統標準輸入設備構造BufferedReader對象 PrintWriter write = new PrintWriter(socket.getOutputStream()); // 由Socket對象獲得輸出流,並構造PrintWriter對象 //三、獲取輸入流,並讀取服務器端的響應信息 BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); // 由Socket對象獲得輸入流,並構造相應的BufferedReader對象 String readline, infix, expression; readline = br.readLine(); // 從系統標準輸入讀入一字符串 MyBC theTrans = new MyBC(readline); infix = theTrans.doTrans(); StringBuilder newInfix = new StringBuilder(infix.replace(" ","")); for (int i = 1; i < infix.length()+(i+1)/2 ; i=i+2) { newInfix.insert(i," "); } System.out.println("後綴表達式:" + newInfix); expression=newInfix.toString(); while (!readline.equals("end")) { // 若從標準輸入讀入的字符串爲 "end"則中止循環 write.println(expression); // 將從系統標準輸入讀入的字符串輸出到Server write.flush(); // 刷新輸出流,使Server立刻收到該字符串 System.out.println("收到服務器的消息:" + in.readLine()); // 從Server讀入一字符串,並打印到標準輸出上 readline = br.readLine(); // 從系統標準輸入讀入一字符串 } // 繼續循環 //四、關閉資源 write.close(); // 關閉Socket輸出流 in.close(); // 關閉Socket輸入流 socket.close(); // 關閉Socket } catch (Exception e) { System.out.println(e);//輸出異常 } finally { } } }
實驗截圖:
步驟 | 耗時 | 百分比 |
---|---|---|
功能實現 | 55min | 12.5% |
測試 | 25min | 15.6% |
分析總結 | 20min | 12.5% |