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

    实验内容及步骤

    任务一:两人一组结对编程:

    1. 参考http://www.cnblogs.com/rocedu/p/6766748.html#SECDSA
    2. 结对实现中缀表达式转后缀表达式的功能 MyBC.java
    3. 结对实现从上面功能中获取的表达式中实现后缀表达式求值的功能,调用MyDC.java
    4. 上传测试代码运行结果截图和码云链接

    实现中缀表达式转后缀表达式

    import java.util.Stack;
    import java.util.StringTokenizer;
    
    public class MyBC {
        /** 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 */
        Stack<Integer> stack=new Stack<Integer>();;
    
        String expression;
        public void setExpression(String str) {
            expression=str;
        }
        public  String changedWay() {
            String changedExpression = "";
            Stack signStack = new Stack();// 操作符栈
            for (int i = 0; i < expression.length(); i++) {
                char c = expression.charAt(i);
                if (c >= '0' && c <= '9') {
                    changedExpression=changedExpression+c;
                }
                else if (c == '+' || c == '-' || c == '*' || c == '/') {
                    changedExpression=changedExpression+" ";//分隔数字
                    if (signStack.empty()) {
                        signStack.push(c);
                    }
                    else if (judgeValue(c) >= judgeValue((Character) signStack.peek())) {//优先级高于或等于,运算符号均进栈
                        signStack.push(c);
                    }
                    else {
                        changedExpression=changedExpression+(char)signStack.pop();
                        signStack.push(c);
                    }
                }
                else if (c=='(') {
                    signStack.push(c);
                }
                else if (c==')') {
                    while((char)signStack.peek()!='(') {
                        changedExpression=changedExpression+" "+signStack.pop();
                    }
                    signStack.pop();
                }
            }
            while(!signStack.empty()){
                changedExpression=changedExpression+" "+String.valueOf(signStack.pop());
            }
            return changedExpression;
        }
    
        private static int judgeValue(char c) {
            int value = 0;
            switch (c) {
                case '(':
                    value = 1;
                    break;
                case '+':
                case '-':
                    value = 2;
                    break;
                case '*':
                case '/':
                    value = 3;
                    break;
                case ')':
                    value = 4;
                default:
                    value = 0;
            }
            return value;
        }
        public int evaluate (String expr)
        {//后缀表达式的运算方法
            int op1, op2, result = 0;
            String token;
            StringTokenizer tokenizer = new StringTokenizer (expr);//使用StringTokenizer类分解String对象的字符序列,默认为空格符...
            //此时tokenizer为一个分析器
            while (tokenizer.hasMoreTokens()) {
                token = tokenizer.nextToken();
                if (isOperator(token))
                {
                    op2 = (stack.pop()).intValue();//出栈
                    op1 = (stack.pop()).intValue();//出栈
                    result = evalSingleOp (token.charAt(0), op1, op2);//String对象第一个字符转换为char类型的方法为:str.charAt(0)
                    stack.push (new Integer(result));//进栈
                }
                else {
                    stack.push(new Integer(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;
        }
    }
    • 实现截图为:

    任务二:两人一组结对编程:

    1. 参考http://www.cnblogs.com/rocedu/p/6766748.html#SECDSA
    2. 结对实现中缀表达式转后缀表达式的功能 MyBC.java
    3. 结对实现从上面功能中获取的表达式中实现后缀表达式求值的功能,调用MyDC.java
    4. 上传测试代码运行结果截图和码云链接
    • 获取本机IP地址:DESKTOP-HN1B8O2/172.30.2.248
    netAddress address_3=InetAddress.getLocalHost();
    System.out.println(address_3.toString());
    • 结对伙伴的IP为:172.30.4.50 所选端口为:1111
    • 负责客服端的构建,实现代码为:
    • 选用AES加密算法
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.net.Socket;
    import java.util.*;
    
    public class Client_2Socket {
        public static void main(String[] args) {
            Socket Client_2Socket;
            DataInputStream Client_2in=null;
            DataOutputStream Client_2out=null;
            String expr,str;
            Scanner scanner=new Scanner(System.in);
            System.out.println("请输入表达式:");
            str=scanner.nextLine();
            MyBC mybc=new MyBC();
            mybc.setExpression(str);
            expr=mybc.changedWay();
            try {
                Client_2Socket=new Socket("172.30.2.248",5353);
                Client_2in=new DataInputStream(Client_2Socket.getInputStream());
                Client_2out=new DataOutputStream(Client_2Socket.getOutputStream());
                Client_2out.writeUTF(expr);
                String s=Client_2in.readUTF();
                System.out.println("服务器回复:
    "+s);
            }
            catch (Exception e) {
                System.out.println("服务器已断开"+e);
            }
        }
    }
    • 结对伙伴负责的服务器端代码为:
    import java.io.*;
    import java.net.*;
    import java.util.*;
    
    public class Server_2 {
        public static void main(String[] args) {
            ServerSocket Server_2forClient_2=null;
            Socket SocketOnServer_2=null;
            DataOutputStream Server_2out=null;
            DataInputStream Server_2in=null;
            try {
                Server_2forClient_2=new ServerSocket(5353);
            }
            catch (IOException e1) {
                System.out.println(e1);
                //e1.printStackTrace();
            }
            try {
                System.out.println("等待客户端呼叫……");
                SocketOnServer_2=Server_2forClient_2.accept();
                Server_2out=new DataOutputStream(SocketOnServer_2.getOutputStream());
                Server_2in=new DataInputStream(SocketOnServer_2.getInputStream());
                String expr=Server_2in.readUTF();
                System.out.println("服务器接收到表达式:"+expr);
                int result;
                MyBC mybc=new MyBC();
                result=mybc.evaluate(expr);
                Server_2out.writeUTF("后缀表达式:"+expr+",运算结果为:"+result);
                Thread.sleep(500);
            }
            catch (Exception e2) {
                System.out.println("客户端已断开"+e2);
            }
        }
    }
    • 实验截图

    任务三:加密结对编程:1人负责客户端,一人负责服务器

    1. 注意责任归宿,要会通过测试证明自己没有问题
    2. 基于Java Socket实现客户端/服务器功能,传输方式用TCP
    3. 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密后通过网络把密文发送给服务器
    4. 服务器接收到后缀表达式表达式后,进行解密(和客户端协商密钥,可以用数组保存),然后调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
    5. 客户端显示服务器发送过来的结果
    6. 上传测试结果截图和码云链接
    • 思路:密文通过TCP传输,而AES密钥通过机密通道传输。
    • 负责客服端的构建,代码为:
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.net.Socket;
    import java.util.*;
    
    public class Client_3 {
        public static void main(String[] args) {
            Socket Client_2Socket;
            DataInputStream Client_2in=null;
            DataOutputStream Client_2out=null;
            String expr=null;
            String str=null;
            String Ciphertext=null;
            Scanner scanner=new Scanner(System.in);
            System.out.println("请输入表达式:");
            str=scanner.nextLine();
            MyBC mybc=new MyBC();
            mybc.setExpression(str);
            expr=mybc.changedWay();
            try {
                AES.produceAESKey();//生成AES密钥
                byte[]cc= AES.EncryptionAES(expr);//需要传输的密文,数组形式传输。
                Ciphertext = Base64.getEncoder().encodeToString(cc);//将加密后的密文由byte[]转换为String类型
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                Client_2Socket=new Socket("172.30.2.248",5300);
                Client_2in=new DataInputStream(Client_2Socket.getInputStream());
                Client_2out=new DataOutputStream(Client_2Socket.getOutputStream());
                Client_2out.writeUTF(Ciphertext);
                String s=Client_2in.readUTF();
                System.out.println("服务器回复:
    "+s);
            }
            catch (Exception e) {
                System.out.println("服务器已断开"+e);
            }
        }
    }
    • 结对伙伴负责构建服务器,代码为:
    import sun.security.krb5.internal.crypto.Aes128;
    
    import java.io.*;
    import java.net.*;
    import java.util.*;
    
    public class Server_3 {
        public static void main(String[] args) {
            ServerSocket Server_2forClient_2=null;
            Socket SocketOnServer_2=null;
            DataOutputStream Server_2out=null;
            DataInputStream Server_2in=null;
            try {
                Server_2forClient_2=new ServerSocket(5300);
            }
            catch (IOException e1) {
                System.out.println(e1);
            }
            try {
                System.out.println("等待客户端呼叫……");
                SocketOnServer_2=Server_2forClient_2.accept();
                Server_2out=new DataOutputStream(SocketOnServer_2.getOutputStream());
                Server_2in=new DataInputStream(SocketOnServer_2.getInputStream());
                String Ciphertext=Server_2in.readUTF();//密文
                byte[] data= Base64.getDecoder().decode(Ciphertext);
                String expr= AES.DecryptionAES(data);
                System.out.println("服务器接收到表达式:"+expr);
                int result;
                MyBC mybc=new MyBC();
                result=mybc.evaluate(expr);
                Server_2out.writeUTF("后缀表达式:"+expr+",运算结果为:"+result);
                Thread.sleep(500);
            }
            catch (Exception e2) {
                System.out.println("客户端已断开"+e2);
            }
        }
    }
    • 实验截图

    任务四:密钥分发结对编程:1人负责客户端,一人负责服务器

    1. 注意责任归宿,要会通过测试证明自己没有问题
    2. 基于Java Socket实现客户端/服务器功能,传输方式用TCP
    3. 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密通过网络把密文发送给服务器
    4. 客户端和服务器用DH算法进行3DES或AES算法的密钥交换
    5. 服务器接收到后缀表达式表达式后,进行解密,然后调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
    6. 客户端显示服务器发送过来的结果
    7. 上传测试结果截图和码云链接

    DH算法相关链接:

    • DH算法原理
    • 密钥交换算法DH(Java实现)

    • 密钥交换实现过程:
      1. 由消息发送的一方构建密钥,这里由甲方构建密钥。
      2. 由构建密钥的一方向对方公布其公钥,这里由甲方向乙方发布公钥。
      3. 由消息接收的一方通过对方公钥构建自身密钥,这里由乙方使用甲方公钥构建乙方密钥。
      4. 由消息接收的一方向对方公布其公钥,这里由乙方向甲方公布公钥。
    • 使用密钥协定创建共享密钥截图:

    • 使用创建的共享密钥就可以对AES的密钥进行加解密。因为生成的共享密钥为DESede密钥类型,则使用DESede加解密模式,密钥为共享密钥其余不变。即将共享密钥保存于文件Key_DESede_DH.dat中即可。

    • 实现关键代码:

    SecretKeySpec k=new  SecretKeySpec(sb,"DESede");
            FileOutputStream  f=new FileOutputStream("A_Key_DESede_DH.dat");//指定产生密钥输出流文件
            ObjectOutputStream b=new  ObjectOutputStream(f);//将对象序列化,以流的方式进行处理
            b.writeObject(k);//通过以对象序列化方式将密钥保存在文件中
            

    任务五:完整性校验结对编程:1人负责客户端,一人负责服务器

    1. 注意责任归宿,要会通过测试证明自己没有问题
    2. 基于Java Socket实现客户端/服务器功能,传输方式用TCP
    3. 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密通过网络把密文和明文的MD5値发送给服务器
    4. 客户端和服务器用DH算法进行3DES或AES算法的密钥交换
    5. 服务器接收到后缀表达式表达式后,进行解密,解密后计算明文的MD5值,和客户端传来的MD5进行比较,一致则调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
    6. 客户端显示服务器发送过来的结果
    7. 上传测试结果截图和码云链接
    • 实验截图:

    遇到问题及解决方案

    • 问题1:无法进行测试

    • 问题1解决方案:测试前应填入数据,再进行测试
    • 问题2:出现java.net.SocketException: Connection reset,客户端输出文件出错
    • 问题2解决方案:该异常在客户端和服务器端均有可能发生,引起该异常的原因有两个,第一个就是如果一端的Socket被关闭(或主动关闭或者因为异常退出而引起的关闭),另一端仍发送数据,发送的第一个数据包引发该异常(Connect reset by peer)。另一个是一端退出,但退出时并未关闭该连接,另一端如果在从连接中读数据则抛出该异常(Connection reset)。简单的说就是在连接断开后的读和写操作引起的。 在读取信息时不应该关闭客户端。

    PSP

    步骤 耗时(h) 百分比
    设计 2 20%
    代码实现 5 50%
    测试 2 20%
    分析总结 1 10%

    实验小结

    本次实验过程中出现了很多问题,反反复复折腾了几天,不过在不断地从书中网上查询解决问题的过程中,收获颇丰。其实不管是学习生活还是今后工作,有时候需要适当地逼一下自己,可能在某一方面投入90%精力但仍不见希望时,我们需要做的可能就是再努力10%。这应该是本学期最后一次实验了,虽然Java实验真的磨人,不过不论从知识的提升还是耐力的磨练,总算是有所收获,还是挺感谢娄老师。希望自己以后也能屏住最后一口气,撑住往前走。

  • 相关阅读:
    荧光机理的应用——光学式农药测量技术及系统设计
    滤光片应用——红外吸收粉尘传感器的设计
    磁靶向纳米Fe3O4-TiO2复合物对肝癌细胞的光催化杀伤效应研究
    常用荧光染料的激发波长和发射波长
    光害
    一文解读虚拟化服务器
    一文解读PRA
    主数据建设的挑战与发展
    数字孪生技术变革
    intellij idea:配置maven 3.8.2(intellij idea 2021.2)
  • 原文地址:https://www.cnblogs.com/axyaxy/p/10946422.html
Copyright © 2011-2022 走看看