上傳測試代碼運行結果截圖和碼雲連接html
將運算符寫在兩個操做數中間的表達式,稱爲「中綴表達式」,如1+2(3-4)+5。在中綴表達式中,運算符具備不一樣的優先級,圓括號用於改變運算符的運算次序,因此求值過程不能直接按照從左到右的順序進行。
將運算符寫在兩個操做數以後的表達式稱爲「後綴表達式」,如上面的中綴表達式可轉換爲後綴表達式1 2 3 4 - + 5 +。後綴表達式中沒有括號,並且運算符沒有優先級。後綴表達式的求值過程可以嚴格地從左到右按順序進行,符合運算器的求值規律。
表達式求值算法分兩步進行:①中綴轉後綴;②求後綴表達式的值。
①中綴轉後綴的算法可描述爲:java
設置一個運算符棧,設置一個後綴表達式字符串;
從左到右依次對中綴表達式中的每一個字符ch分別進行如下處理,直至表達式結束:
若ch是左括號‘(’,將其入棧;
若ch是數字,將其後連續若干數字添加到後綴表達式字符串以後,並添加空格做爲分隔符;
若ch是運算符,先將棧頂若干優先級高於ch的運算符出棧,添加到後綴表達式字符串以後,再將ch入棧。當‘(’運算符在棧中時,它的優先級最低。
若ch是‘)’,則若干運算符所有出棧,直到出棧的是左括號,一對括號匹配。
若表達式結束,將棧中運算符所有出棧,添加到後綴表達式字符串以後。
中綴轉後綴的代碼爲:算法
public static String toPostfix(String expr){ MyStack<String> stack = new MyStack<>(expr.length()); String postfix = ""; int i = 0; while(i<expr.length()){ char ch = expr.charAt(i); switch (ch){ case '+': case '-':while(!stack.isEmpty() && !stack.get().equals("(")) postfix += stack.pop(); //postfix += " "; stack.push(ch + ""); i++; break; case '*': case '/':while (!stack.isEmpty() && (stack.get().equals("*")||stack.get().equals("/"))) postfix += stack.pop(); //postfix += " "; stack.push(ch + ""); i++; break; case '(':stack.push(ch + ""); i++; break; case ')':String out = stack.pop(); while(out!=null && !out.equals("(")){ postfix += out; out = stack.pop(); //postfix += " "; } i++; break; default:while(i < expr.length() && ch>='0' && ch<='9'){ postfix += ch; i++; if(i<expr.length()) ch = expr.charAt(i); } postfix += " "; } } while (!stack.isEmpty()) postfix += stack.pop(); return postfix; }
②後綴表達式求值的算法可描述爲express
設置一個操做數棧,從左向右依次對後綴表達式字符串中的每一個字符ch進行處理;
若ch是數字,先將其後連續若干數字轉化爲整數,再將該整數入棧;
若ch是運算符,出棧兩個值進行運算,運算結果再入棧;
重複以上步驟,直至後綴表達式結束,棧中最後一個數字就是所求表達式的值。
後綴表達式求值的代碼爲:編程
public int value(String postfix){ Stack<Integer> stack = new Stack(); int i = 0, result = 0; while(i < postfix.length()){ char ch = postfix.charAt(i); if(ch>='0' && ch<='9'){ result = 0; while(ch!=' '){ result = result*10 + Integer.parseInt(ch+""); i++; ch = postfix.charAt(i); } i++; stack.push(new Integer(result)); } else{ int y = stack.pop().intValue(); int x = stack.pop().intValue(); switch (ch){ case ADD: result = x + y; break; case SUBTRACT: result = x - y; break; case MULTIPLY: result = x * y; break; case DIVIDE: result = x / y; } stack.push(new Integer(result)); i++; } } return stack.pop().intValue(); }
最後添加測試代碼便可:數組
public class NewMyDCTester { public static void main(String [] args) { String expression; int result; try { Scanner in = new Scanner(System.in); NewMyDC evaluator = new NewMyDC(); System.out.println ("Enter a valid postfix expression: "); expression = in.nextLine(); String postfix = MyBC.toPostfix(expression); System.out.println ("The postfix expression is :" + postfix); result = evaluator.value (postfix); System.out.println ("That expression equals :" + result); } catch (Exception IOException) { System.out.println("Input exception reported"); } } }
運行結果以下:
安全
結對編程:1人負責客戶端,一人負責服務器
0.注意責任歸宿,要會經過測試證實本身沒有問題
1.基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
2.客戶端讓用戶輸入中綴表達式,而後把中綴表達式調用MyBC.java的功能轉化爲後綴表達式,把後綴表達式經過網絡發送給服務器
3.服務器接收到後綴表達式,調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
4.客戶端顯示服務器發送過來的結果
5.上傳測試結果截圖和碼雲連接服務器
java.net.Socket與java.net.ServerSocket網絡
『java.net.Socket』:併發
套接字是一個網絡鏈接的端點。在java中,使用java.net.Socket對象來表示一個套接字。
要建立一個套接字,可使用Socket的構造方法,如:public Socket(java.lang.String host, int port)。其中,host是遠程機器名或IP地址,port是遠程應用程序的端口號。
一旦成功建立了Socket類的一個實例,就可使用它發送或接收字節流。要發送字節流,必須先調用Socket類的getOutputStream方法來獲取一個java.io.OutputStream對象。要向遠程應用程序發送文本,一般要從返回的OutputStream對象構建一個java.io.PrintWriter對象。要接收來自鏈接的另外一端的字節流,能夠調用Socket類的getInputStream方法,它返回一個java.io.InputStream。
如下代碼建立了一個客戶端:
// 一、建立客戶端Socket,指定服務器地址和端口 Socket socket=new Socket("127.0.0.1",5200); //Socket socket = new Socket("192.168.1.115", 5209); System.out.println("客戶端啓動成功"); // 二、獲取輸出流,向服務器端發送信息 // 向本機的5200端口發出客戶請求 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; readline = br.readLine(); // 從系統標準輸入讀入一字符串 while (!readline.equals("end")) { // 若從標準輸入讀入的字符串爲 "end"則中止循環 write.println(readline); // 將從系統標準輸入讀入的字符串輸出到Server write.flush(); // 刷新輸出流,使Server立刻收到該字符串 System.out.println("Client:" + readline); // 在系統標準輸出上打印讀入的字符串 System.out.println("Server:" + in.readLine()); // 從Server讀入一字符串,並打印到標準輸出上 readline = br.readLine(); // 從系統標準輸入讀入一字符串 } // 繼續循環 //四、關閉資源 write.close(); // 關閉Socket輸出流 in.close(); // 關閉Socket輸入流 socket.close(); // 關閉Socket
『java.net.ServerSocket』:
ServerSocket是服務器套接字的一個實現。ServerSocket和Socket不一樣,服務器套接字的角色是,等待來自客戶端的鏈接請求。一旦服務器套接字得到了一個鏈接請求,它就會建立一個Socket實例,以處理和客戶端的通訊。
如下代碼建立了一個服務器:
//搭建服務器端 public static void main(String[] args) throws IOException{ SocketService socketService = new SocketService(); //一、a)建立一個服務器端Socket,即SocketService socketService.oneServer(); } public void oneServer(){ try{ ServerSocket server=null; try{ server=new ServerSocket(5200); //b)指定綁定的端口,並監聽此端口。 System.out.println("服務器啓動成功"); //建立一個ServerSocket在端口5209監聽客戶請求 }catch(Exception e) { System.out.println("沒有啓動監聽:"+e); //出錯,打印出錯信息 } Socket socket=null; try{ socket=server.accept(); //二、調用accept()方法開始監聽,等待客戶端的鏈接 //使用accept()阻塞等待客戶請求,有客戶 //請求到來則產生一個Socket對象,並繼續執行 }catch(Exception e) { System.out.println("Error."+e); //出錯,打印出錯信息 } //三、獲取輸入流,並讀取客戶端信息 String line; BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream())); //由Socket對象獲得輸入流,並構造相應的BufferedReader對象 PrintWriter writer=new PrintWriter(socket.getOutputStream()); //由Socket對象獲得輸出流,並構造PrintWriter對象 BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); //由系統標準輸入設備構造BufferedReader對象 System.out.println("Client:"+in.readLine()); //在標準輸出上打印從客戶端讀入的字符串 line=br.readLine(); //從標準輸入讀入一字符串 //四、獲取輸出流,響應客戶端的請求 while(!line.equals("end")){ //若是該字符串爲 "bye",則中止循環 writer.println(line); //向客戶端輸出該字符串 writer.flush(); //刷新輸出流,使Client立刻收到該字符串 System.out.println("Server:"+line); //在系統標準輸出上打印讀入的字符串 System.out.println("Client:"+in.readLine()); //從Client讀入一字符串,並打印到標準輸出上 line=br.readLine(); //從系統標準輸入讀入一字符串 } //繼續循環 //五、關閉資源 writer.close(); //關閉Socket輸出流 in.close(); //關閉Socket輸入流 socket.close(); //關閉Socket server.close(); //關閉ServerSocket }catch(Exception e) {//出錯,打印出錯信息 System.out.println("Error."+e); } }
建立了客戶端和服務器,調用任務一中的中綴表達式轉後綴表達式與後綴表達式求值的方法便可。運行結果以下:
加密結對編程:1人負責客戶端,一人負責服務器
0.注意責任歸宿,要會經過測試證實本身沒有問題
1.基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
2.客戶端讓用戶輸入中綴表達式,而後把中綴表達式調用MyBC.java的功能轉化爲後綴表達式,把後綴表達式用3DES或AES算法加密後經過網絡把密文發送給服務器
3.服務器接收到後綴表達式表達式後,進行解密(和客戶端協商密鑰,能夠用數組保存),而後調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
4.客戶端顯示服務器發送過來的結果
5.上傳測試結果截圖和碼雲連接
實現DES加密主要有如下幾個步驟:
對稱密鑰的生成和保存;
使用對稱密鑰進行加密和解密;
從文件中獲取加密時使用的密鑰,使用密鑰進行解密;
客戶端加密併發送至服務器部分的代碼以下:
KeyGenerator kg = KeyGenerator.getInstance("DESede"); kg.init(168); SecretKey k = kg.generateKey(); byte[] ptext2 = k.getEncoded(); Socket socket = new Socket("127.0.0.1", 4421); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true); BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); //RSA算法,使用服務器端的公鑰對DES的密鑰進行加密 FileInputStream f3 = new FileInputStream("Skey_RSA_pub.dat"); ObjectInputStream b2 = new ObjectInputStream(f3); RSAPublicKey pbk = (RSAPublicKey) b2.readObject(); BigInteger e = pbk.getPublicExponent(); BigInteger n = pbk.getModulus(); BigInteger m = new BigInteger(ptext2); BigInteger c = m.modPow(e, n); String cs = c.toString(); out.println(cs); // 經過網絡將加密後的祕鑰傳送到服務器 System.out.print("請輸入待發送的數據:"); //用DES加密明文獲得密文 String s = stdin.readLine(); // 從鍵盤讀入待發送的數據 String postfix = MyBC.toPostfix(s); Cipher cp = Cipher.getInstance("DESede"); cp.init(Cipher.ENCRYPT_MODE, k); byte ptext[] = postfix.getBytes("UTF8"); byte ctext[] = cp.doFinal(ptext); String str = parseByte2HexStr(ctext); out.println(str); // 經過網絡將密文傳送到服務器 服務器解密、計算併發送至客戶端部分的代碼以下: String line = in.readLine(); BigInteger cipher = new BigInteger(line); FileInputStream f = new FileInputStream("Skey_RSA_priv.dat"); ObjectInputStream b = new ObjectInputStream(f); RSAPrivateKey prk = (RSAPrivateKey) b.readObject(); BigInteger d = prk.getPrivateExponent(); BigInteger n = prk.getModulus();//mod n BigInteger m = cipher.modPow(d, n);//m=d (mod n) System.out.println("d= " + d); System.out.println("n= " + n); System.out.println("m= " + m); byte[] keykb = m.toByteArray(); // 使用DES對密文進行解密 String readline = in.readLine();//讀取客戶端傳送來的數據 FileInputStream f2 = new FileInputStream("keykb1.dat"); int num2 = f2.available(); byte[] ctext = parseHexStr2Byte(readline); Key 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");//編碼轉換 System.out.println("從客戶端接收到信息爲:" + p); //打印解密結果 NewMyDC evaluator = new NewMyDC(); int _result = evaluator.value(p); out.println("Echo:" + _result); out.close(); in.close(); link.close();
運行截圖以下:
密鑰分發結對編程:1人負責客戶端,一人負責服務器
0.注意責任歸宿,要會經過測試證實本身沒有問題
1.基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
2.客戶端讓用戶輸入中綴表達式,而後把中綴表達式調用MyBC.java的功能轉化爲後綴表達式,把後綴表達式用3DES或AES算法加密經過網絡把密文發送給服務器
3.客戶端和服務器用DH算法進行3DES或AES算法的密鑰交換
4.服務器接收到後綴表達式表達式後,進行解密,而後調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
5.客戶端顯示服務器發送過來的結果
6.上傳測試結果截圖和碼雲連接
執行密鑰協定的標準算法是DH算法(Diffie-Hellman算法),分爲如下兩步:
建立DH公鑰和私鑰;
建立共享密鑰。
建立DH公鑰和私鑰:
實驗體會與總結
本次實驗是具體的網絡編程,難度很大,按照同窗的博客一步步作才作完了實驗,在作的過程當中也學到了許多知識點。
中綴表達式與後綴表達式
將運算符寫在兩個操做數中間的表達式
將運算符寫在兩個操做數以後的表達式
表達式求值算法:①中綴轉後綴;②求後綴表達式的值
中綴轉後綴的算法可描述爲:
設置一個運算符棧,設置一個後綴表達式字符串;
從左到右依次對中綴表達式中的每一個字符ch分別進行如下處理,直至表達式結束:
若ch是左括號‘(’,將其入棧;
若ch是數字,將其後連續若干數字添加到後綴表達式字符串以後,並添加空格做爲分隔符;
若ch是運算符,先將棧頂若干優先級高於ch的運算符出棧,添加到後綴表達式字符串以後,再將ch入棧。當‘(’運算符在棧中時,它的優先級最低。
若ch是‘)’,則若干運算符所有出棧,直到出棧的是左括號,一對括號匹配。
若表達式結束,將棧中運算符所有出棧,添加到後綴表達式字符串以後。
後綴表達式求值的算法可描述爲(參考:婁老師的博客):
設置一個操做數棧,從左向右依次對後綴表達式字符串中的每一個字符ch進行處理;
若ch是數字,先將其後連續若干數字轉化爲整數,再將該整數入棧;
若ch是運算符,出棧兩個值進行運算,運算結果再入棧;
重複以上步驟,直至後綴表達式結束,棧中最後一個數字就是所求表達式的值。
實現DES加密步驟:
對稱密鑰的生成和保存;
使用對稱密鑰進行加密和解密;
從文件中獲取加密時使用的密鑰,使用密鑰進行解密;
RSA算法,使用服務器端的公鑰對DES的密鑰進行加密
KeyGenerator kg = KeyGenerator.getInstance("DESede"); kg.init(168); SecretKey k = kg.generateKey(); byte[] ptext2 = k.getEncoded(); Socket socket = new Socket("127.0.0.1", 4421); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true); BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); 用DES加密明文獲得密文 FileInputStream f3 = new FileInputStream("Skey_RSA_pub.dat"); ObjectInputStream b2 = new ObjectInputStream(f3); RSAPublicKey pbk = (RSAPublicKey) b2.readObject(); BigInteger e = pbk.getPublicExponent(); BigInteger n = pbk.getModulus(); BigInteger m = new BigInteger(ptext2); BigInteger c = m.modPow(e, n); String cs = c.toString(); out.println(cs); // 經過網絡將加密後的祕鑰傳送到服務器 System.out.print("請輸入待發送的數據:");
MD5算法返回實現指定摘要算法的 MessageDigest對象:
String aline3 = in.readLine(); String x = p; MessageDigest m2 = MessageDigest.getInstance("MD5");