• 20175325 《JAVA程序设计》实验五《网络编程与安全》实验报告


    20175325 《JAVA程序设计》实验五《网络编程与安全》实验报告

    一、实验报告封面
    课程:Java程序设计 班级:1753班 姓名:石淦铭
    学号:20175325
    指导教师:娄嘉鹏 实验日期:2019年5月28日
    实验序号:实验五
    实验名称:网络编程与安全

    二、实验内容及步骤:

    (一)、实验一
    1、题目:

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

    2、解答:

    • 由中缀式求得后缀式可以使用栈,伪代码如下:
      • 设立一个栈,存放运算符,首先栈为空;
      • 从左到右扫描中缀式,若遇到操作数,直接输出,并输出一个空格作为两个操作数的分隔符;
      • 若遇到运算符,则与栈顶比较,比栈顶级别高则进栈,否则退出栈顶元素并输出,然后输出一个空格作分隔符;
      • 若遇到左括号,进栈;若遇到右括号,则一直退栈输出,直到退到左括号止。
      • 当栈变成空时,输出的结果即为后缀表达式。
    • 后缀表达式求值的伪代码如下:
      • 设置一个操作数栈,开始栈为空;
      • 从左到右扫描后缀表达式,遇操作数,进栈;
      • 若遇运算符,则从栈中退出两个元素,先退出的放到运算符的右边,后退出的放到运算符左边,运算后的结果再进栈,直到后缀表达式扫描完毕。
      • 重复以上步骤,直至后缀表达式结束,栈中最后一个数字就是所求表达式的值。
    • 实验代码:
      MyBC:
    public class MyBC {
        private Stack theStack;
        private String input;
        private String output = "";
    
        public MyBC(String in) {
            input = in;
            int stackSize = input.length();
            theStack = new Stack(stackSize);
        }
    
        public String doTrans() {
            for (int j = 0; j < input.length(); j++) {
                char ch = input.charAt(j);
                switch (ch) {
                    case '+':
                    case '-':
                        gotOper(ch, 1);
                        break;
                    case '*':
                    case '/':
                        gotOper(ch, 2);
                        break;
                    case '(':
                        theStack.push(ch);
                        break;
                    case ')':
                        gotParen(ch);
                        break;
                    default:
                        output = output + ch;
                        break;
                }
            }
            while (!theStack.isEmpty()) {
                output = output + theStack.pop();
            }
            return output;
        }
    
        public void gotOper(char opThis, int prec1) {
            while (!theStack.isEmpty()) {
                char opTop = theStack.pop();
                if (opTop == '(') {
                    theStack.push(opTop);
                    break;
                } else {
                    int prec2;
                    if (opTop == '+' || opTop == '-')
                        prec2 = 1;
                    else
                        prec2 = 2;
                    if (prec2 < prec1) {
                        theStack.push(opTop);
                        break;
                    } else
                        output = output + opTop;
                }
            }
            theStack.push(opThis);
        }
    
        public void gotParen(char ch) {
            while (!theStack.isEmpty()) {
                char chx = theStack.pop();
                if (chx == '(')
                    break;
                else
                    output = output + chx;
            }
        }
    
        class Stack {
            private int maxSize;
            private char[] stackArray;
            private int top;
    
            public Stack(int max) {
                maxSize = max;
                stackArray = new char[maxSize];
                top = -1;
            }
    
            public void push(char j) {
                stackArray[++top] = j;
            }
    
            public char pop() {
                return stackArray[top--];
            }
    
            public char peek() {
                return stackArray[top];
            }
    
            public boolean isEmpty() {
                return (top == -1);
            }
        }
    }
    

    MyDC:

    import java.util.StringTokenizer;
    import java.util.Stack;
    public class MyDC {
        private final char ADD = '+';
        private final char SUBTRACT = '-';
        private final char MULTIPLY = '*';
        private final char DIVIDE = '/';
        private Stack<Integer> stack;
        public MyDC() {
            stack = new Stack<Integer>();
        }
        public int evaluate(String expr) {
            int op1, op2, result = 0;
            String token;
            StringTokenizer tokenizer = new StringTokenizer(expr);
            while (tokenizer.hasMoreTokens()) {
                token = tokenizer.nextToken();
                //如果是运算符,调用isOperator
                if (isOperator(token)) {
                    //从栈中弹出操作数2
                    op2 = stack.pop();
                    //从栈中弹出操作数1
                    op1 = stack.pop();
                    //根据运算符和两个操作数调用evalSingleOp计算result;
                    result=evalSingleOp(token.charAt(0), op1, op2);
                    //计算result入栈;
                    stack.push(result);
                } else//如果是操作数
                    //操作数入栈;
                    stack.push(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、题目:

    • 结对编程:1人负责客户端,一人负责服务器
    • 注意责任归宿,要会通过测试证明自己没有问题
    • 基于Java Socket实现客户端/服务器功能,传输方式用TCP
    • 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式通过网络发送给服务器
    • 服务器接收到后缀表达式,调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
    • 客户端显示服务器发送过来的结果
    • 上传测试结果截图和码云链接

    2、解答:

    • 对象建立方法:使用Socket类
    • Socket构造方法:Socket(String host,int port)
    • ServerSocket对象与服务器端套接字
    • 构造方法:ServerSocket(int port)
    • 使用方法accept()将客户端的套接字和服务器端的套接字连接起来
    • 套接字通信基本原则:
      • 服务器启动一个专门的线程,在该线程中和客户的套接字建立连接
      • 套接字的输入流在读取信息时可能发生阻塞,客户端和服务器端都需要在一个单独的线程中读取信息
    • ServerSocket和Socket不同,服务器套接字的角色是,等待来自客户端的连接请求。一旦服务器套接字获得了一个连接请求,它就会创建一个Socket实例,以处理和客户端的通信。

    客户端:

    import java.net.*;
    import java.io.*;
    public class Client
    {
        public static void main(String srgs[]) throws Exception
        {
            try
            {
                Socket socket=new Socket("127.0.0.1",5325);
                System.out.println("客户端启动成功");
                // 向本机的10001端口发出客户请求
                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, infix, expression;
                readline = br.readLine(); 
                MyBC theTrans = new MyBC(readline);
                infix = theTrans.doTrans();
                StringBuilder newInfix = new StringBuilder(infix.replace(" ",""));
                for (int i = 1; i < infix.length()+(i+1)/2 ; i=i+2) {
                    newInfix.insert(i," ");
                }
                System.out.println("后缀表达式为: " + newInfix);
                expression=newInfix.toString();
    
                while (!readline.equals("end")) {
                    // 若从标准输入读入的字符串为 "end"则停止循环
                    write.println(expression);
                    // 将从系统标准输入读入的字符串输出到Server
                    write.flush();
                    // 刷新输出流,使Server马上收到该字符串
                    System.out.println("客户端发来的消息为:" + expression);
                    // 在系统标准输出上打印读入的字符串
                    System.out.println("服务器发来的结果为:" + in.readLine());
                    // 从Server读入一字符串,并打印到标准输出上
                    readline = br.readLine(); // 从系统标准输入读入一字符串
                } // 继续循环
                write.close(); // 关闭Socket输出流
                in.close(); // 关闭Socket输入流
                socket.close(); // 关闭Socket
            }
            catch (Exception e)
            {
                System.out.println(e);//输出异常
            }
            finally
            {
    
            }
    
        }
    }
    

    服务端:

    import java.net.*;
    import java.io.*;
    
    public class Server{
        public static void main(String srgs[]) throws Exception
        {
            ServerSocket sc = null;
            Socket socket=null;
            try
            {
                MyDC evaluator = new MyDC();
                sc= new ServerSocket(5325);//创建服务器套接字
                System.out.println("端口号:" + sc.getLocalPort());
                System.out.println("服务器启动");
                socket = sc.accept();   //等待客户端连接
                System.out.println("已经建立连接");//获得网络输入流对象的引用
                BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));//获得网络输出流对象的引用
                PrintWriter out=new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);
                String aline2=in.readLine();
                System.out.println("客户端发来的信息为:"+aline2);
    
                int ans = evaluator.evaluate(aline2);
                out.println(ans);
                System.out.println("result = "+ans);
            } catch (Exception e) {
                System.out.println(e);
            }
        }
        public static byte[] parseHexStr2Byte(String hexStr)
        {
            if (hexStr.length() < 1)
                return null;
            byte[] result = new byte[hexStr.length()/2];
            for (int i = 0;i< hexStr.length()/2; i++)
            {
                int high = Integer.parseInt(hexStr.substring(i*2, i*2+1 ), 16);
                int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16);
                result[i] = (byte) (high * 16 + low);
            }
            return result;
        }
    }
    

    结果截图:

    (三)、实验三
    1、题目:

    • 加密结对编程:1人负责客户端,一人负责服务器
    • 注意责任归宿,要会通过测试证明自己没有问题
    • 基于Java Socket实现客户端/服务器功能,传输方式用TCP
    • 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密后通过网络把密文发送给服务器
    • 服务器接收到后缀表达式表达式后,进行解密(和客户端协商密钥,可以用数组保存),然后调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
    • 客户端显示服务器发送过来的结果
    • 上传测试结果截图和码云链接

    2、解答:

    (四)、实验四
    1、题目:

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

    2、解答:

    • DH算法:
      • DH密钥交换算法的安全性基于有限域上的离散对数难题。基于这种安全性,通过DH算法进行密钥分配,使得消息的收发双方可以安全地交换一个密钥,再通过这个密钥对数据进行加密和解密处理。
      • 创建DH公钥和私钥;
      • 再创建共享密钥。
    • 使用KeyPairGenerator类创建DH公钥和私钥
    • 码云链接:
      https://gitee.com/sgm5/text1/commit/d0b6bc4ae80ea6862fc098017fb0133035e52694
    • 实验截图:

    (五)、实验五
    1、题目:

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

    2、解答:

    三、PSP:

    步骤 耗时 百分比
    需求分析 30 11%
    设计 50 19%
    代码实现 90 34%
    测试 45 17%
    分析总结 50 19%
  • 相关阅读:
    13 原型链_继承_this大总结_函数一定是对象,对象不一定是函数
    12 贪吃蛇游戏
    实现wiki访问
    11 第三个阶段js高级_原型
    JZOJ.5257【NOIP2017模拟8.11】小X的佛光
    模板——权值线段树(逆序对)
    LCA模板
    笛卡尔树——神奇的“二叉搜索堆”
    JZOJ.5246【NOIP2017模拟8.8】Trip
    JZOJ.5236【NOIP2017模拟8.7】利普希茨
  • 原文地址:https://www.cnblogs.com/sgm5/p/10940794.html
Copyright © 2020-2023  润新知