Unique~sgm

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%

posted on 2019-05-28 22:46  胖铭鸭  阅读(184)  评论(0编辑  收藏  举报

导航