zoukankan      html  css  js  c++  java
  • 2017-2018-2 20165226 实验五《网络编程与安全》实验报告

    实验五《网络编程与安全》

    实验目的

    • 一、结对实现中缀表达式转后缀表达式的功能 ,从上面功能中获取的表达式中实现后缀表达式求值的功能

    • 二、 基于Java Socket实现客户端/服务器功能,传输方式用TCP,客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式通过网络发送给服务器

    • 三、服务器接收到后缀表达式表达式后,进行解密(和客户端协商密钥,可以用数组保存),然后调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端

    • 四、客户端和服务器用DH算法进行3DES或AES算法的密钥交换

    • 五、客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密通过网络把密文发送给服务器

    实验内容及步骤

    (一)结对实现中缀表达式转后缀表达式的功能 ,从上面功能中获取的表达式中实现后缀表达式求值的功能

    1、设置IP地址

    • 通过输入ipconfig指令来查询IP地址

    2、结对实现中缀表达式转后缀表达式的功能 MyBC.java,进行测试

    3、 结对实现从上面功能中获取的表达式中实现后缀表达式求值的功能,调用MyDC.java

    4、知识点

    • 中缀式转化后缀式

      • 设立一个栈,存放运算符,首先栈为空;
      • 从左到右扫描中缀式,若遇到操作数,直接输出,并输出一个空格作为两个操作数的分隔符;
      • 若遇到运算符,则与栈顶比较,比栈顶级别高则进栈,否则退出栈顶元素并输出,然后输出一个空格作分隔符;
      • 若遇到左括号,进栈;若遇到右括号,则一直退栈输出,直到退到左括号止。
        当栈变成空时,输出的结果即为后缀表达式。
    • 算符优先法求解表达式

      • 建立符号运算的优先级关系表

      • 设操作栈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" 的时候, 客户端将终止
    ");
            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("请输入: 	");
                    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)!=''){
                        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" 的时候, 客户端将终止
    ");
            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("请输入: 	");
                    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)!=''){
                        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("请输入: 	");
            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) != '') {
                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:无法进行测试

    • 问题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实验真的磨人,不过不论从知识的提升还是耐力的磨练,总算是有所收获,还是挺感谢娄老师。希望自己以后也能屏住最后一口气,撑住往前走。

  • 相关阅读:
    结构体 和 类 的区别
    运算符重载
    迭代器
    HttpClient 同时上传多个文件及参数, 同时利用 Web Api 接收
    JS 上传图片时实现预览
    web api 如何通过接收文件流的方式,接收客户端及前端上传的文件
    同时上传参数及图片到 Web Api
    jsp jstl标签库核心标签
    jsp jstl的使用
    jsp 简单标签开发
  • 原文地址:https://www.cnblogs.com/musea/p/9074269.html
Copyright © 2011-2022 走看看