2017-2018-2 20165226 實驗五《網絡編程與安全》實驗報告

實驗五《網絡編程與安全》

實驗目的

  • 1、結對實現中綴表達式轉後綴表達式的功能 ,從上面功能中獲取的表達式中實現後綴表達式求值的功能java

  • 2、 基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP,客戶端讓用戶輸入中綴表達式,而後把中綴表達式調用MyBC.java的功能轉化爲後綴表達式,把後綴表達式經過網絡發送給服務器算法

  • 3、服務器接收到後綴表達式表達式後,進行解密(和客戶端協商密鑰,能夠用數組保存),而後調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端編程

  • 4、客戶端和服務器用DH算法進行3DES或AES算法的密鑰交換數組

  • 5、客戶端讓用戶輸入中綴表達式,而後把中綴表達式調用MyBC.java的功能轉化爲後綴表達式,把後綴表達式用3DES或AES算法加密經過網絡把密文發送給服務器安全

實驗內容及步驟

(一)結對實現中綴表達式轉後綴表達式的功能 ,從上面功能中獲取的表達式中實現後綴表達式求值的功能

一、設置IP地址

  • 經過輸入ipconfig指令來查詢IP地址

二、結對實現中綴表達式轉後綴表達式的功能 MyBC.java,進行測試

三、 結對實現從上面功能中獲取的表達式中實現後綴表達式求值的功能,調用MyDC.java

四、知識點

  • 中綴式轉化後綴式
    • 設立一個棧,存放運算符,首先棧爲空;
    • 從左到右掃描中綴式,若遇到操做數,直接輸出,並輸出一個空格做爲兩個操做數的分隔符;
    • 若遇到運算符,則與棧頂比較,比棧頂級別高則進棧,不然退出棧頂元素並輸出,而後輸出一個空格做分隔符;
    • 若遇到左括號,進棧;若遇到右括號,則一直退棧輸出,直到退到左括號止。
      當棧變成空時,輸出的結果即爲後綴表達式。
  • 算符優先法求解表達式
    • 創建符號運算的優先級關係表
      服務器

    • 設操做棧OPND、運算符棧OPTR,最低符號#壓進OPTR
    • 讀入字符C,C如果操做數, 進OPND;如果運算符,與OPTR棧頂元素(A)比較,根據算符優先級,決定如何處理:
      • A<C, C壓入OPTR棧;
      • A=C, A從OPTR出棧;
      • A>C,A出棧,從OPND依次彈出兩個操做數y、x, 計算Z=x A y,Z壓入OPND棧。C壓進OPTR.
    • 重複上步操做直至表達式結果網絡

(二)結對編程

基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP,客戶端讓用戶輸入中綴表達式,而後把中綴表達式調用MyBC.java的功能轉化爲後綴表達式,把後綴表達式經過網絡發送給服務器;服務器接收到後綴表達式,調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端; 客戶端顯示服務器發送過來的結果
  • Client
/**
*Created by xiang on 2018/5/23.
*/
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
public class Client {
  public static final String IP_ADDR = "127.0.0.1";//服務器地址
    public static final int PORT = 12345;//服務器端口號
    public static void main(String[] args) {
        System.out.println("客戶端啓動...");
        System.out.println("當接收到服務器端字符爲 \"OK\" 的時候, 客戶端將終止\n");
        while (true) {
            Socket socket = null;
            try {
                //建立一個流套接字並將其鏈接到指定主機上的指定端口號
                socket = new Socket(IP_ADDR, PORT);
                //讀取服務器端數據
                DataInputStream input = new DataInputStream(socket.getInputStream());
                //向服務器端發送數據
                DataOutputStream out = new DataOutputStream(socket.getOutputStream());
                System.out.print("請輸入: \t");
                String str = new BufferedReader(new InputStreamReader(System.in)).readLine();
                MyBC turner = new MyBC();
                String str1 = turner.turn(str);
                int length=0,i=0;
                while(str1.charAt(i)!='\0'){
                    length++;
                    i++;
                }
                String str2 = str1.substring(1,length-1);
                out.writeUTF(str2);
                String ret = input.readUTF();
                System.out.println("服務器端返回過來的是: " + ret);
                /*if ("OK".equals(ret)) {
                    System.out.println("客戶端將關閉鏈接");
                    Thread.sleep(500);
                    break;
                }*/
                out.close();
                input.close();
            } catch (Exception e) {
                System.out.println("客戶端異常:" + e.getMessage());
            } finally {
                if (socket != null) {
                    try {
                        socket.close();
                    } catch (IOException e) {
                        socket = null;
                        System.out.println("客戶端 finally 異常:" + e.getMessage());
                    }
                }
            }
        }
    }
}
  • 測試結果

(三)加密結對編程

  1. 基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
  2. 客戶端讓用戶輸入中綴表達式,而後把中綴表達式調用MyBC.java的功能轉化爲後綴表達式,把後綴表達式用3DES或AES算法加密後經過網絡把密文發送給服務器
  3. 服務器接收到後綴表達式表達式後,進行解密(和客戶端協商密鑰,能夠用數組保存),而後調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
  4. 客戶端顯示服務器發送過來的結果
  • client3
/**
*Created by xiang on 2018/5/24.
*/
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
public class Client2 {
    public static final String IP_ADDR = "127.0.0.1";//服務器地址
    public static final int PORT = 1234;//服務器端口號
    public static void main(String[] args) {
        System.out.println("客戶端啓動...");
        System.out.println("當接收到服務器端字符爲 \"OK\" 的時候, 客戶端將終止\n");
        while (true) {
            Socket socket = null;
            try {
                //建立一個流套接字並將其鏈接到指定主機上的指定端口號
                socket = new Socket(IP_ADDR, PORT);
                //讀取服務器端數據
                DataInputStream input = new DataInputStream(socket.getInputStream());
                //向服務器端發送數據
                DataOutputStream out = new DataOutputStream(socket.getOutputStream());
                System.out.print("請輸入: \t");
                String str = new BufferedReader(new InputStreamReader(System.in)).readLine();
                MyBC turner = new MyBC();
                Skey_DES skey_des = new Skey_DES();
                skey_des.key_DES();
                Skey_kb skey_kb = new Skey_kb();
                skey_kb.key();
        /*產生密鑰*/
                SEnc sEnc = new SEnc();
                String str1 = turner.turn(str);
                int length=0,i=0;
                while(str1.charAt(i)!='\0'){
                    length++;
                    i++;
                }
                String str2 = str1.substring(1,length-1);
                out.writeUTF(str2);
                String ret = input.readUTF();
                System.out.println("服務器端返回過來的是: " + ret);
                // 如接收到 "OK" 則斷開鏈接
                /*if ("OK".equals(ret)) {
                    System.out.println("客戶端將關閉鏈接");
                    Thread.sleep(500);
                    break;
                }*/
                out.close();
                input.close();
            } catch (Exception e) {
                System.out.println("客戶端異常:" + e.getMessage());
            } finally {
                if (socket != null) {
                    try {
                        socket.close();
                    } catch (IOException e) {
                        socket = null;
                        System.out.println("客戶端 finally 異常:" + e.getMessage());
                    }
                }
            }
        }
    }
}
  • SEnc
/**
*Created by xiang on 2018/5/24.
*/
import java.io.*;
import java.security.*;
import javax.crypto.*;
public class SEnc{
    static String s;
    public SEnc(String s){
        this.s = s;
    }
    public void  encrypt(){
        try{
        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);
        for(int i=0;i<ctext.length;i++){
            System.out.print(ctext[i] +",");
        }
        FileOutputStream f2=new FileOutputStream("SEnc.dat");
        f2.write(ctext);
    }catch(Exception e){
            System.out.println(e);
        }
    }
}
  • 結果

(四)密鑰分發結對編程

  1. 基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
  2. 客戶端讓用戶輸入中綴表達式,而後把中綴表達式調用MyBC.java的功能轉化爲後綴表達式,把後綴表達式用3DES或AES算法加密經過網絡把密文發送給服務器
  3. 客戶端和服務器用DH算法進行3DES或AES算法的密鑰交換
  4. 服務器接收到後綴表達式表達式後,進行解密,而後調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
  5. 客戶端顯示服務器發送過來的結果
  • Client4
/**
*Created by xiang on 2018/5/26.
*/
import java.io.*;
import java.net.Socket;
public class Client4 {
    public static void main(String[] args) {
        Socket s = null;
        try {
            s = new Socket("172.30.0.159", 4004);
        }catch (IOException e) {
            System.out.println("未鏈接到服務器");
        }
    try
    {
        DataInputStream input = new DataInputStream(s.getInputStream());
        System.out.print("請輸入: \t");
        String str = new BufferedReader(new InputStreamReader(System.in)).readLine();
        MyBC turner = new MyBC();
        String str1 = turner.turn(str);
        int length = 0, i = 0;
        while (str1.charAt(i) != '\0') {
            length++;
            i++;
        }
        String str2 = str1.substring(1, length - 1);
        SEnc senc = new SEnc(str2);//指定後綴表達式爲明文字符串
        senc.encrypt();//加密
    }catch(Exception e) {
        System.out.println("客戶端異常:" + e.getMessage());
    }
        File sendfile = new File("SEnc.dat");
        File sendfile1 = new File("Keykb1.dat");
        /**定義文件輸入流,用來打開、讀取即將要發送的文件*/
        FileInputStream fis = null;
        FileInputStream fis1 = null;
        /**定義byte數組來做爲數據包的存儲數據包*/
        byte[] buffer = new byte[4096 * 5];
        byte[] buffer1 = new byte[4096 * 5];
        /**定義輸出流,使用socket的outputStream對數據包進行輸出*/
        OutputStream os = null;
        if(!sendfile.exists() || !sendfile1.exists()){
            System.out.println("客戶端:要發送的文件不存在");
            return;
        }
        try {
            fis = new FileInputStream(sendfile);
            fis1 = new FileInputStream(sendfile1);
        } catch (FileNotFoundException e1) {
            e1.printStackTrace();
        }
        try {
            PrintStream ps = new PrintStream(s.getOutputStream());
            ps.println("111/#" + sendfile.getName() + "/#" + fis.available());
            ps.flush();
        } catch (IOException e) {
            System.out.println("服務器鏈接中斷");
        }
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }傳輸的關鍵代碼
        try {
            /**獲取socket的OutputStream,以便向其中寫入數據包*/
            os = s.getOutputStream();
            /** size 用來記錄每次讀取文件的大小*/
            int size = 0;
            /**使用while循環讀取文件,直到文件讀取結束*/
            while((size = fis.read(buffer)) != -1){
                System.out.println("客戶端發送數據包,大小爲" + size);
                /**向輸出流中寫入剛剛讀到的數據包*/
                os.write(buffer, 0, size);
                /**刷新一下*/
                os.flush();
            }
        } catch (FileNotFoundException e) {
            System.out.println("客戶端讀取文件出錯");
        } catch (IOException e) {
            System.out.println("客戶端輸出文件出錯");
        }finally{
            try {
                if(fis != null)
                    fis.close();
            } catch (IOException e) {
                System.out.println("客戶端文件關閉出錯");
            }//catch (IOException e)
        }//finally
        try {
            PrintStream ps1 = new PrintStream(s.getOutputStream());
            ps1.println("111/#" + sendfile1.getName() + "/#" + fis1.available());
            ps1.flush();
        } catch (IOException e) {
            System.out.println("服務器鏈接中斷");
        }
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
        try {
            /**獲取socket的OutputStream,以便向其中寫入數據包*/
            os = s.getOutputStream();
            /** size 用來記錄每次讀取文件的大小*/
            int size = 0;
            /**使用while循環讀取文件,直到文件讀取結束*/
            while((size = fis1.read(buffer1)) != -1){
                System.out.println("客戶端發送數據包,大小爲" + size);
                /**向輸出流中寫入剛剛讀到的數據包*/
                os.write(buffer1, 0, size);
                /**刷新一下*/
                os.flush();
            }
        } catch (FileNotFoundException e) {
            System.out.println("客戶端讀取文件出錯");
        } catch (IOException e) {
            System.out.println("客戶端輸出文件出錯");
        }finally{
            try {
                if(fis1 != null)
                    fis1.close();
            } catch (IOException e) {
                System.out.println("客戶端文件關閉出錯");
            }//catch (IOException e)
        }//finally
        try{
            DataInputStream input = new DataInputStream(s.getInputStream());
            String ret = input.readUTF();
            System.out.println("服務器端返回過來的是: " + ret);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if (s != null) {
                try {
                    s.close();
                } catch (IOException e) {
                    s = null;
                    System.out.println("客戶端 finally 異常:" + e.getMessage());
                }
            }
        }
    }//public static void main(String[] args)
}//public class ClientSend
  • 結果

(五)密鑰分發結對編程

  1. 基於Java Socket實現客戶端/服務器功能,傳輸方式用TCP
  2. 客戶端讓用戶輸入中綴表達式,而後把中綴表達式調用MyBC.java的功能轉化爲後綴表達式,把後綴表達式用3DES或AES算法加密經過網絡把密文發送給服務器
  3. 客戶端和服務器用DH算法進行3DES或AES算法的密鑰交換
  4. 服務器接收到後綴表達式表達式後,進行解密,而後調用MyDC.java的功能計算後綴表達式的值,把結果發送給客戶端
  5. 客戶端顯示服務器發送過來的結果
  • Client5
import java.io.*;
import java.net.*;
import java.security.MessageDigest;
public class Client5 {
    public static void main(String args[]) throws Exception {
        MyBC turner = new MyBC();
        Skey_DES skey_des = new Skey_DES();
        skey_des.key_DES();
        Skey_kb skey_kb = new Skey_kb();
        skey_kb.key();
        /*產生密鑰*/
        SEnc sEnc = new SEnc();
        try {
            Socket socket = new Socket("127.0.0.1", 4700);
//向本機的4700端口發出客戶請求
            BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
//由系統標準輸入設備構造BufferedReader對象
            PrintWriter os = new PrintWriter(socket.getOutputStream());
//由Socket對象獲得輸出流,並構造PrintWriter對象
            BufferedReader is = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//由Socket對象獲得輸入流,並構造相應的BufferedReader對象
            String readline;
            readline =sin.readLine();
            //從系統標準輸入讀入一字符串
            String x = readline;
            // 將客戶端明文的Hash值傳送給服務器
            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("明文MD5值爲:" + result);
            os.println(result);//經過網絡將明文的Hash函數值傳送到服務器
            // String str = is.readLine();// 從網絡輸入流讀取結果
            System.out.println("從服務器接收到的結果爲:" + result); // 輸出服務器返回的結果
            while (!readline.equals("bye")) {
//若從標準輸入讀入的字符串爲 "bye"則中止循環
                readline = SEnc.Enc(turner.turn(readline));
                os.println(readline);
                /*把中綴表達式調用MyBC.java的功能轉化爲後綴表達式,把後綴表達式用3DES加密後經過網絡發送給服務器*/
                //將從系統標準輸入讀入的字符串輸出到Server
                os.flush();
                //刷新輸出流,使Server立刻收到該字符串
                System.out.println("Client:" + readline);
                //在系統標準輸出上打印讀入的字符串
                System.out.println("Server:" + is.readLine());
                //從Server讀入一字符串,並打印到標準輸出上
                readline = sin.readLine(); //從系統標準輸入讀入一字符串
            } //繼續循環
            os.close(); //關閉Socket輸出流
            is.close(); //關閉Socket輸入流
            socket.close(); //關閉Socket
        } catch (Exception e) {
            System.out.println("Error" + e); //出錯,則打印出錯信息
        }
    }
}
  • 結果

遇到問題及解決方案

  • 問題1:沒法進行測試
    socket

  • 問題1解決方案:測試前應填入數據,再進行測試
  • 問題2:進行測試時,報錯input exception reported
    函數

  • 問題2解決方案:搜了一下,發現是格式的問題,字符間應有空格相鏈接
    學習

  • 問題3:出現java.net.SocketException: Connection reset,客戶端輸出文件出錯

  • 問題3解決方案:該異常在客戶端和服務器端均有可能發生,引發該異常的緣由有兩個,第一個就是若是一端的Socket被關閉(或主動關閉或者由於異常退出而引發的關閉),另外一端仍發送數據,發送的第一個數據包引起該異常(Connect reset by peer)。另外一個是一端退出,但退出時並未關閉該鏈接,另外一端若是在從鏈接中讀數據則拋出該異常(Connection reset)。簡單的說就是在鏈接斷開後的讀和寫操做引發的。 在讀取信息時不該該關閉客戶端。

  • 問題4:沒法運行程序,報錯

  • 問題4解決方案:從新啓動,或者換個端口,好比以前是4004,就能夠換成1234

統計PSP(Personal Software Process)時間:

步驟 耗時(h) 百分比
設計 2 20%
代碼實現 5 50%
測試 2 20%
分析總結 1 10%

實驗小結

本次實驗過程當中出現了不少問題,反反覆覆折騰了一週,不過在不斷地從書中網上查詢解決問題的過程當中,收穫頗豐。其實不論是學習生活仍是從此工做,有時候須要適當地逼一下本身,可能在某一方面投入90%精力但仍不見但願時,咱們須要作的可能就是再努力10%。這應該是本學期最後一次實驗了,雖然Java實驗真的磨人,不過不論從知識的提高仍是耐力的磨練,總算是有所收穫,仍是挺感謝婁老師。但願本身之後也能屏住最後一口氣,撐住往前走。

相關文章
相關標籤/搜索