20155303 實驗五 網絡編程與安全
目錄
- 任務一:
- 編寫MyBC.java實現中綴表達式轉后綴表達式的功能
- 編寫MyDC.java實現從上面功能中獲取的表達式中實現后綴表達式求值的功能
- 任務二:
- 結對編程:一人負責客戶端,另一人負責服務器
- 注意責任歸宿,要會通過測試證明自己沒有問題
- 基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
- 客戶端讓用戶輸入中綴表達式,然后把中綴表達式調用MyBC.java的功能轉化為后綴表達式,把后綴表達式通過網絡發送給服務器
- 服務器接收到后綴表達式,調用MyDC.java的功能計算后綴表達式的值,把結果發送給客戶端
- 客戶端顯示服務器發送過來的結果
- 任務三:
- 客戶端讓用戶輸入中綴表達式,然后把中綴表達式調用MyBC.java的功能轉化為后綴表達式,把后綴表達式用3DES或AES算法加密后通過網絡把密文發送給服務器
- 服務器接收到后綴表達式表達式后,進行解密(和客戶端協商密鑰,可以用數組保存),然后調用MyDC.java的功能計算后綴表達式的值,把結果發送給客戶端
- 其他要求同任務二
- 任務四:
- 客戶端和服務器用DH算法進行3DES或AES算法的密鑰交換
- 其他要求同任務三
- 任務五:
- 服務器接收到后綴表達式表達式后,進行解密,解密后計算明文的MD5值,和客戶端傳來的MD5進行比較,一致則調用MyDC.java的功能計算后綴表達式的值,把結果發送給客戶端
- 其他要求同任務四
- 任務六:
- 客戶端功能用Android實現
- 實驗體會與總結
- 參考資料
任務一
題目:①編寫MyBC.java實現中綴表達式轉后綴表達式的功能;②編寫MyDC.java實現從上面功能中獲取的表達式中實現后綴表達式求值的功能
- 將運算符寫在兩個操作數中間的表達式,稱為“中綴表達式”,如
1+2*(3-4)+5
。在中綴表達式中,運算符具有不同的優先級,圓括號用於改變運算符的運算次序,所以求值過程不能直接按照從左到右的順序進行。 - 將運算符寫在兩個操作數之后的表達式稱為“后綴表達式”,如上面的中綴表達式可轉換為后綴表達式
1 2 3 4 - * + 5 +
。后綴表達式中沒有括號,而且運算符沒有優先級。后綴表達式的求值過程能夠嚴格地從左到右按順序進行,符合運算器的求值規律。 - 表達式求值算法分兩步進行:①中綴轉后綴;②求后綴表達式的值。
①中綴轉后綴的算法可描述為:
- 設置一個運算符棧,設置一個后綴表達式字符串;
- 從左到右依次對中綴表達式中的每個字符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;
}
②后綴表達式求值的算法可描述為(參考:婁老師的博客):
- 設置一個操作數棧,從左向右依次對后綴表達式字符串中的每個字符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");
}
}
}
運行結果如下:
任務二
題目:①結對編程:一人負責客戶端,另一人負責服務器;②注意責任歸宿,要會通過測試證明自己沒有問題;③基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP;④客戶端讓用戶輸入中綴表達式,然后把中綴表達式調用MyBC.java的功能轉化為后綴表達式,把后綴表達式通過網絡發送給服務器;⑤服務器接收到后綴表達式,調用MyDC.java的功能計算后綴表達式的值,把結果發送給客戶端;⑥客戶端顯示服務器發送過來的結果
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。
以下代碼創建了一個客戶端:
// 1、創建客戶端Socket,指定服務器地址和端口
Socket socket=new Socket("127.0.0.1",5200);
//Socket socket = new Socket("192.168.1.115", 5209);
System.out.println("客戶端啟動成功");
// 2、獲取輸出流,向服務器端發送信息
// 向本機的5200端口發出客戶請求
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// 由系統標准輸入設備構造BufferedReader對象
PrintWriter write = new PrintWriter(socket.getOutputStream());
// 由Socket對象得到輸出流,並構造PrintWriter對象
//3、獲取輸入流,並讀取服務器端的響應信息
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(); // 從系統標准輸入讀入一字符串
} // 繼續循環
//4、關閉資源
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();
//1、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();
//2、調用accept()方法開始監聽,等待客戶端的連接
//使用accept()阻塞等待客戶請求,有客戶
//請求到來則產生一個Socket對象,並繼續執行
}catch(Exception e) {
System.out.println("Error."+e);
//出錯,打印出錯信息
}
//3、獲取輸入流,並讀取客戶端信息
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();
//從標准輸入讀入一字符串
//4、獲取輸出流,響應客戶端的請求
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();
//從系統標准輸入讀入一字符串
} //繼續循環
//5、關閉資源
writer.close(); //關閉Socket輸出流
in.close(); //關閉Socket輸入流
socket.close(); //關閉Socket
server.close(); //關閉ServerSocket
}catch(Exception e) {//出錯,打印出錯信息
System.out.println("Error."+e);
}
}
創建了客戶端和服務器,調用任務一中的中綴表達式轉后綴表達式與后綴表達式求值的方法即可。運行結果如下:
任務三
題目:①客戶端讓用戶輸入中綴表達式,然后把中綴表達式調用MyBC.java的功能轉化為后綴表達式,把后綴表達式用3DES或AES算法加密后通過網絡把密文發送給服務器;②服務器接收到后綴表達式表達式后,進行解密(和客戶端協商密鑰,可以用數組保存),然后調用MyDC.java的功能計算后綴表達式的值,把結果發送給客戶端。其他要求同任務二。
-
實現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();
運行截圖如下:
任務四
題目:客戶端和服務器用DH算法進行3DES或AES算法的密鑰交換。其他要求同任務三。
-
執行密鑰協定的標准算法是DH算法(Diffie-Hellman算法),分為以下兩步:
- 創建DH公鑰和私鑰;
- 創建共享密鑰。
-
創建DH公鑰和私鑰:
public class Key_DH{
private static final byte skip1024ModulusBytes[] = {
(byte)0xF4, (byte)0x88, (byte)0xFD, (byte)0x58,
(byte)0x4E, (byte)0x49, (byte)0xDB, (byte)0xCD,
(byte)0x20, (byte)0xB4, (byte)0x9D, (byte)0xE4,
(byte)0x91, (byte)0x07, (byte)0x36, (byte)0x6B,
(byte)0x33, (byte)0x6C, (byte)0x38, (byte)0x0D,
(byte)0x45, (byte)0x1D, (byte)0x0F, (byte)0x7C,
(byte)0x88, (byte)0xB3, (byte)0x1C, (byte)0x7C,
(byte)0x5B, (byte)0x2D, (byte)0x8E, (byte)0xF6,
(byte)0xF3, (byte)0xC9, (byte)0x23, (byte)0xC0,
(byte)0x43, (byte)0xF0, (byte)0xA5, (byte)0x5B,
(byte)0x18, (byte)0x8D, (byte)0x8E, (byte)0xBB,
(byte)0x55, (byte)0x8C, (byte)0xB8, (byte)0x5D,
(byte)0x38, (byte)0xD3, (byte)0x34, (byte)0xFD,
(byte)0x7C, (byte)0x17, (byte)0x57, (byte)0x43,
(byte)0xA3, (byte)0x1D, (byte)0x18, (byte)0x6C,
(byte)0xDE, (byte)0x33, (byte)0x21, (byte)0x2C,
(byte)0xB5, (byte)0x2A, (byte)0xFF, (byte)0x3C,
(byte)0xE1, (byte)0xB1, (byte)0x29, (byte)0x40,
(byte)0x18, (byte)0x11, (byte)0x8D, (byte)0x7C,
(byte)0x84, (byte)0xA7, (byte)0x0A, (byte)0x72,
(byte)0xD6, (byte)0x86, (byte)0xC4, (byte)0x03,
(byte)0x19, (byte)0xC8, (byte)0x07, (byte)0x29,
(byte)0x7A, (byte)0xCA, (byte)0x95, (byte)0x0C,
(byte)0xD9, (byte)0x96, (byte)0x9F, (byte)0xAB,
(byte)0xD0, (byte)0x0A, (byte)0x50, (byte)0x9B,
(byte)0x02, (byte)0x46, (byte)0xD3, (byte)0x08,
(byte)0x3D, (byte)0x66, (byte)0xA4, (byte)0x5D,
(byte)0x41, (byte)0x9F, (byte)0x9C, (byte)0x7C,
(byte)0xBD, (byte)0x89, (byte)0x4B, (byte)0x22,
(byte)0x19, (byte)0x26, (byte)0xBA, (byte)0xAB,
(byte)0xA2, (byte)0x5E, (byte)0xC3, (byte)0x55,
(byte)0xE9, (byte)0x2F, (byte)0x78, (byte)0xC7
};
// The SKIP 1024 bit modulus
private static final BigInteger skip1024Modulus
= new BigInteger(1, skip1024ModulusBytes);
// The base used with the SKIP 1024 bit modulus
private static final BigInteger skip1024Base = BigInteger.valueOf(2);
public static void main(String args[ ]) throws Exception{
DHParameterSpec DHP=
new DHParameterSpec(skip1024Modulus,skip1024Base);
KeyPairGenerator kpg= KeyPairGenerator.getInstance("DH");
kpg.initialize(DHP);
KeyPair kp=kpg.genKeyPair();
PublicKey pbk=kp.getPublic();
PrivateKey prk=kp.getPrivate();
// 保存公鑰
FileOutputStream f1=new FileOutputStream(args[0]);
ObjectOutputStream b1=new ObjectOutputStream(f1);
b1.writeObject(pbk);
// 保存私鑰
FileOutputStream f2=new FileOutputStream(args[1]);
ObjectOutputStream b2=new ObjectOutputStream(f2);
b2.writeObject(prk);
}
}
- 創建共享密鑰:
public class KeyAgree{
public static void main(String args[ ]) throws Exception{
// 讀取對方的DH公鑰
FileInputStream f1=new FileInputStream(args[0]);
ObjectInputStream b1=new ObjectInputStream(f1);
PublicKey pbk=(PublicKey)b1.readObject( );
//讀取自己的DH私鑰
FileInputStream f2=new FileInputStream(args[1]);
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();
for(int i=0;i<sb.length;i++){
System.out.print(sb[i]+",");
}
SecretKeySpec k=new SecretKeySpec(sb,"DESede");
}
}
運行結果如下:
任務五
題目:服務器接收到后綴表達式表達式后,進行解密,解密后計算明文的MD5值,和客戶端傳來的MD5進行比較,一致則調用MyDC.java的功能計算后綴表達式的值,把結果發送給客戶端。其他要求同任務四。
-
可以使用Java計算指定字符串的消息摘要。java.security包中的MessageDigest類提供了計算消息摘要的方法,首先生成對象,執行其update()方法可以將原始數據傳遞給該對象,然后執行其digest( )方法即可得到消息摘要。
-
在客戶端添加如下代碼:
// 將客戶端明文的Hash值傳送給服務器
String x = postfix;
MessageDigest m2 = MessageDigest.getInstance("MD5");
m2.update(x.getBytes());
byte a[] = m2.digest();
String result = "";
for (int i = 0; i < a.length; i++) {
result += Integer.toHexString((0x000000ff & a[i]) | 0xffffff00).substring(6);
}
System.out.println(result);
out.println(result);//通過網絡將明文的Hash函數值傳送到服務器
str = in.readLine();// 從網絡輸入流讀取結果
System.out.println("從服務器接收到的結果為:" + str); // 輸出服務器返回的結果
- 在服務器添加如下代碼:
// 使用Hash函數檢測明文完整性
String aline3 = in.readLine();
String x = p;
MessageDigest m2 = MessageDigest.getInstance("MD5");//使用MD5算法返回實現指定摘要算法的 MessageDigest對象
m2.update(x.getBytes());
byte a[] = m2.digest();
String result = "";
for (int i = 0; i < a.length; i++) {
result += Integer.toHexString((0x000000ff & a[i]) | 0xffffff00).substring(6);
}
System.out.println(result);
if (aline3.equals(result)) {
System.out.println("匹配成功");
}
運行結果如下:
任務六
客戶端功能用Android實現
-
由於服務端通常運行在有固定IP的服務器上,所以可以直接將PC作為服務器。
-
下面的代碼顯示了如何運用Socket類建立,實現連接到指定IP端口並獲取服務端發送的數據的功能。該程序創建連接后,將接收到的數據顯示在文本框中。
-
建立客戶端程序如下:
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
public class MainActivity extends AppCompatActivity {
private TextView text1;
private Button but1;
private EditText edit1;
private final String DEBUG_TAG="mySocketAct";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text1 = (TextView)findViewById(R.id.text1);
but1 = (Button)findViewById(R.id.but1);
edit1 = (EditText) findViewById(R.id.edit);
but1.setOnClickListener(new Button.OnClickListener()
{
@Override
public void onClick(View v){
Socket socket = null;
String mesg = edit1.getText().toString()+"\r\n";
edit1.setText("");
Log.e("dddd","set id");
try{
socket = new Socket("127.0.0.1", 4421);
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);
out.println(mesg);
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String mstr = br.readLine();
if(mstr!=null){
text1.setText(mstr);
}else{
text1.setText("數據錯誤");
}
out.close();
br.close();
socket.close();
}catch (UnknownHostException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}catch (Exception e){
Log.e(DEBUG_TAG, e.toString());
}
}
});
}
}
- 注意:由於使用了網絡連接,還需要在Mainfest文件中添加網絡訪問權限,如下所示:
<uses-permission android:name="android.permission.INTERNET"/>
- 再在客戶端添加中綴表達式轉為后綴表達式和加密的部分即可完成,運行截圖如下:
實驗體會與總結
此次實驗的內容是網絡編程,作為信息安全專業的學生,掌握網絡和安全編程是重點也是基礎。由於第一次接觸相關內容,開始我不太理解如何實現客戶端和服務器,也不知道該怎樣使用java進行加密解密,以達到安全傳輸數據的目的。之后查閱了大量資料,也從圖書館借了相關書籍進行學習,最終和隊友一起完成了全部實驗。
這次實驗讓我深刻認識到結對編程的重要性。與我結對的馬超學長在實驗中發揮了很大的優勢,由於他去年已自學過網絡編程的內容,再加上比我們高一年級,視野也開闊很多。在我們的默契配合下,很快完成了實驗。另外,任務六Android部分的實現則要感謝另一位隊友『他的博客戳這里:)』。我們利用假期時間,合作完成了Android客戶端,合作過程跟他學到了很多,收獲非常大。