zoukankan      html  css  js  c++  java
  • 20165203实验五 网络编程与安全

    20165203实验五 网络编程与安全

    任务一

    两人一组结对编程:
    0. 参考(http://www.cnblogs.com/rocedu/p/6766748.html#SECDSA)

    1. 结对实现中缀表达式转后缀表达式的功能 MyBC.java
    2. 结对实现从上面功能中获取的表达式中实现后缀表达式求值的功能,调用MyDC.java
    3. 上传测试代码运行结果截图和码云链接

    一、实验过程:

    1.根据娄老师的博客,我们先了解前缀表示法、中缀表示法和后缀表示法的概念:

    表达式Exp = S1 + OP + S2(S1 ,S2是两个操作数,OP为运算符)有三种标识方法:

    OP + S1 + S2 为前缀表示法
    S1 + OP + S2 为中缀表示法
    S1 + S2 + OP 为后缀表示法
    例如:Exp = a * b + (c - d / e) * f

    前缀式: + * a b * - c / d e f
    中缀式: a * b + c - d / e * f
    后缀式: a b * c d e / - f * +

    2.中缀表达式转化成后缀表达式的过程:

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

    3.中缀表达式转化成后缀表达式代码实现:

    import java.util.*;
    
    public class NewMyBC {
        String beforeExpression;//未转化的中缀表达式
        String afterExpression = "";//转化后的后缀表达式
        int left = 0;//定义左括号数
        int right = 0;//定义右括号数
    
    
        //判断符号的级别
        public int judgeGrade(char chi) {
            int grade = 0;
            switch (chi) {
                //左括号是第一级
                case '(':
                    grade = 1;
                    break;
                //+和-是第二级
                case '+':
                case '-':
                    grade = 2;
                    break;
                //*和÷是第三级
                case '*':
                case '÷':
                    grade = 3;
                    break;
                // "/"是第四级
                case '/':
                    grade = 4;
                    break;
                //右括号是第五级
                case ')':
                    grade = 5;
                    break;
                default:
                    grade = 0;
            }
            return grade;
        }
    
        public void setBeforeExpression(String exp) {
            beforeExpression=exp;
        }
    
        public String transformWay() {
            Stack stack = new Stack();//新建一个空栈
            int i = 0;
            char op;
            while (i < beforeExpression.length()) {
                op = beforeExpression.charAt(i);//op存放从中缀表达式中取到的元素
                if (op >= '0' && op <= '9') {
                    afterExpression = afterExpression + op;//如果是数字,则直接输出至后缀表达式
                } else if (op == '+' || op == '-' || op == '*' || op == '÷') {
                    afterExpression = afterExpression + ' ';//有运算符,在数字之间加空格
                    // 如果栈为空,则运算符直接入栈
                    if (stack.empty()) {
                        stack.push(op);
                    }
                    //根据符号的级别判断操作
                    else if (judgeGrade(op) > judgeGrade((char) stack.peek())) {
                        stack.push(op);//比栈顶级别高或相等,直接入栈
                    } else {
                        afterExpression = afterExpression + String.valueOf(stack.pop()) + ' ';//否则直接输出
                        i--;
                    }
    
                } else if (op == '(') {
                    left++;
                    stack.push(op);//左括号直接入栈
                } else if (op == ')') {
                    afterExpression += " ";
                    right++;
                    while ((char) stack.peek() != '(') {//右括号,出栈,直到左括号为止
                        afterExpression = afterExpression + String.valueOf(stack.pop()) + " ";
                    }
                    stack.pop();
                }
                i++;
            }
            afterExpression += " ";
            while(!stack.empty()){
                afterExpression=afterExpression+String.valueOf(stack.pop())+" ";
            }
            if (left != right) {
                System.out.println("括号有误");
                System.exit(0);
            }
            return afterExpression;
        }
    }
    
    

    4.后缀表达式求值的步骤:

    • 设置一个操作数栈,开始栈为空;
    • 从左到右扫描后缀表达式,遇操作数,进栈;
    • 若遇运算符,则从栈中退出两个元素,先退出的放到运算符的右边,后退出的放到运算符左边,运算后的结果再进栈,直到后缀表达式扫描完毕。
      此时,栈中仅有一个元素,即为运算的结果。

    5.求值代码:

    
    import java.util.Stack;
    
    public class MyDC {
        /**
         * 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
         */
        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();//将算数表达式分解的
    
                if (isOperator(token))//见下方isOperateor方法,当是运算符的时候进入if语句
                {
                    op2 = (stack.pop()).intValue();
                    op1 = (stack.pop()).intValue();//弹出最上面两个操作数
                    result = evalSingleOp(token.charAt(0), op1, op2);//见下方evaSingleOp方法
                    stack.push(new Integer(result));//将计算结果压栈
                } else{
                    stack.push(new Integer(Integer.parseInt(token)));//操作数入栈
                }
            }
    
            return result;//输出结果
        }
    
        private boolean isOperator(String token)//判断是否为运算符,注意用equal语句比较字符串
        {
            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;
        }
    }
    

    6.测试代码如下:

    
    import java.util.Scanner;
    
    public class MyDCTest {
        public static void main(String[] args) {
            String expression, again;
            int result;
            try {
                Scanner in = new Scanner(System.in);
                do {
                    MyDC evaluator = new MyDC();
                    System.out.println("Enter a valid postfix expression: ");
                    expression = in.nextLine();
                    result = evaluator.evaluate(expression);
                    System.out.println();
                    System.out.println("That expression equals " + result);
    
                    System.out.print("Evaluate another expression [Y/N]? ");
                    again = in.nextLine();
                    System.out.println();
                }
                while (again.equalsIgnoreCase("y"));
            } catch (Exception IOException) {
                System.out.println("Input exception reported");
            }
        }
    }  
    

    二、实验截图:

    三、码云链接

    任务二

    结对编程:1人负责客户端,一人负责服务器
    0. 注意责任归宿,要会通过测试证明自己没有问题

    1. 基于Java Socket实现客户端/服务器功能,传输方式用TCP
    2. 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式通过网络发送给服务器
    3. 服务器接收到后缀表达式,调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
    4. 客户端显示服务器发送过来的结果
    5. 上传测试结果截图和码云链接

    一、实验过程:

    1.经过与搭档协商,我负责客户端(Client.java)部分,搭档负责服务端(Server.java)部分。

    2.客户端部分的代码如下:

    
    import java.io.BufferedReader;
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.*;
    import java.net.*;
    import java.util.*;
    
    public class Client {
        public static void main(String[] args) {
            Socket socket;//套接字对象
            DataInputStream in=null;//输入流
            DataOutputStream out=null;//输出流
            //中缀表达式的输入
            String str;
            Scanner scanner=new Scanner(System.in);
            System.out.println("请输入中缀表达式:");
            str=scanner.nextLine();
            try {
                socket=new Socket("localhost",5203);
                in=new DataInputStream(socket.getInputStream());
                out=new DataOutputStream(socket.getOutputStream());
                out.writeUTF(str);
                String s=in.readUTF();
                System.out.println("结果为:
    "+s);
            }
            catch (Exception e) {
                System.out.println("服务器已断开"+e);
            }
        }
    }
    

    二、实验截图:

    三、码云链接

    任务三

    加密结对编程:1人负责客户端,一人负责服务器
    0. 注意责任归宿,要会通过测试证明自己没有问题

    1. 基于Java Socket实现客户端/服务器功能,传输方式用TCP
    2. 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密后通过网络把密文发送给服务器
    3. 服务器接收到后缀表达式表达式后,进行解密(和客户端协商密钥,可以用数组保存),然后调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
    4. 客户端显示服务器发送过来的结果
    5. 上传测试结果截图和码云链接

    一、实验过程:

    1.我负责客户端,负责编写Client.java.

    2.根据娄老师的密码学算法博客,我和搭档所共同完成的DES算法代码如下:

    import java.io.*;
    import javax.crypto.*;
    public class Skey_DES{
        public static void main(String args[]) throws Exception{
            KeyGenerator kg=KeyGenerator.getInstance("DESede");
            kg.init(168);
            SecretKey k=kg.generateKey( );
            FileOutputStream  f=new FileOutputStream("key1.dat");
            ObjectOutputStream b=new  ObjectOutputStream(f);
            b.writeObject(k);
        }
    }  
    

    3.Client.java代码如下:

    在之前的代码上,增加如下代码:

    import java.io.*;
    import java.net.*;
    import java.util.Scanner;
    
    public class Client {
        public static void main(String[] args) {
            String mess;
            Scanner scanner=new Scanner(System.in);
            System.out.println("请输入问题");
            mess=scanner.nextLine();
            String key="";
            int n=-1;
            byte [] a=new byte[128];
            try{  File f=new File("key1.dat");
                InputStream in = new FileInputStream(f);
                while((n=in.read(a,0,100))!=-1) {
                    key=key+new String (a,0,n);
                }
                in.close();
            }
            catch(IOException e) {
                System.out.println("File read Error"+e);
            }
            System.out.println("客户端提出的问题为:"+mess);
            NewMyBC mybc=new NewMyBC();
            String str;
            mybc.setBeforeExpression(mess);
            str=mybc.transformWay();
            String mi=EncryptDecrypt.AESEncode(key,str);
            System.out.println("客户端加密后密文为:"+mi);
            Socket socket;
            DataInputStream in=null;
            DataOutputStream out=null;
            try{  socket=new Socket("localhost",5006);
                in=new DataInputStream(socket.getInputStream());
                out=new DataOutputStream(socket.getOutputStream());
                BufferedReader in1=new BufferedReader(new InputStreamReader(socket.getInputStream()));
                PrintWriter writer=new PrintWriter(socket.getOutputStream());
                out.writeUTF(mi);
                String  s=in.readUTF();   //in读取信息,堵塞状态
                System.out.println("客户收到服务器的回答为:"+s);
                Thread.sleep(500);
            }
            catch(Exception e) {
                System.out.println("服务器已断开"+e);
            }
        }
    }
    
    
    

    二、实验截图:

    三、码云链接

    任务四

    密钥分发结对编程:1人负责客户端,一人负责服务器
    0. 注意责任归宿,要会通过测试证明自己没有问题

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

    一、实验过程:

    1.我负责客户端,搭档负责服务器端。

    2.根据娄老师的密码学算法博客,我和搭档共同完成的DES算法代码如下:

    
    import java.security.PublicKey;
    import java.security.PrivateKey;
    import java.io.*;
    import javax.crypto.KeyAgreement;
    import javax.crypto.spec.*;
    
    public class KeyAgree{
        public static void main(String args[ ]) throws Exception{
            // 读取对方的DH公钥
            File file=new File("Ckey.dat");
            FileInputStream f1=new FileInputStream("Apub.dat");
            ObjectInputStream b1=new ObjectInputStream(f1);
            PublicKey  pbk=(PublicKey)b1.readObject( );
    //读取自己的DH私钥
            FileInputStream f2=new FileInputStream("Bpri.dat");
            ObjectInputStream b2=new ObjectInputStream(f2);
            PrivateKey  prk=(PrivateKey)b2.readObject( );
            // 执行密钥协定
            KeyAgreement ka=KeyAgreement.getInstance("DH");
            ka.init(prk);
            ka.doPhase(pbk,true);
            //生成共享信息
            byte[ ] sb=ka.generateSecret();
            for(int i=0;i<sb.length;i++){
                System.out.print(sb[i]+",");
            }
            OutputStream out=new FileOutputStream(file);
            out.write(sb);
            out.close();
            SecretKeySpec k=new  SecretKeySpec(sb,"AES");
        }
    }
    
    public class Dapart {
        String dapartstring(String str){
            String s="";
            char c[]=str.toCharArray();
            for(int i=0;i<c.length;i++){
                s=s+c[i]+" ";
            }
            return s;
        }
    }
    

    部分代码,具体代码见码云链接
    3.客户端的代码在实验二的基础上增加如下代码:

     import java.io.*;
    import java.net.*;
    import java.util.Scanner;
    
    public class Client {
        public static void main(String[] args)throws IOException{
            String key="";
            int n=-1;
            byte [] a=new byte[128];
            try{  File f=new File("Ckey.dat");
                InputStream in = new FileInputStream(f);
                while((n=in.read(a,0,100))!=-1) {
                    key=key+new String (a,0,n);
                }
                in.close();
            }
            catch(IOException e) {
                System.out.println("File read Error"+e);
            }
            String mess;
            Scanner scanner=new Scanner(System.in);
            System.out.println("请输入问题:");
            mess=scanner.nextLine();
            NewMyBC mybc=new NewMyBC();
            String str;
            mybc.setBeforeExpression(mess);
            str=mybc.transformWay();
            String m=EncryptDecrypt.AESEncode(key, str);
            System.out.println("客户加密之后的密文为:"+m);
            Socket mysocket;
            DataInputStream in=null;
            DataOutputStream out=null;
            try{  mysocket=new Socket("localhost",6006);
                in=new DataInputStream(mysocket.getInputStream());
                out=new DataOutputStream(mysocket.getOutputStream());
                out.writeUTF(m);
                String  s=in.readUTF();   //in读取信息,堵塞状态
                System.out.println("客户收到服务器的回答为:"+s);
                Thread.sleep(500);
            }
            catch(Exception e) {
                System.out.println("服务器已断开"+e);
            }
        }
    }
    
    
    

    二、实验截图:

    三、码云链接

    任务五

    实验五 网络编程与安全-5
    完整性校验结对编程:1人负责客户端,一人负责服务器
    0. 注意责任归宿,要会通过测试证明自己没有问题

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

    一、实验过程:

    1.我负责客户端,搭档负责服务器端。

    2.根据娄老师的密码学算法博客,我和搭档共同完成的算法代码如下:

    import java.security.*;
    public class DigestPass{
        static String md5(String str) throws Exception{
            MessageDigest m=MessageDigest.getInstance("MD5");
            m.update(str.getBytes("UTF8"));
            byte s[ ]=m.digest( );
            String result="";
            for (int i=0; i<s.length; i++){
                result+=Integer.toHexString((0x000000ff & s[i]) |
                        0xffffff00).substring(6);
            }
            return result;
        }
    }  
    

    3.客户端代码如下:

    就之前实验二的代码添加如下代码:

     import java.net.*;
    import java.util.Scanner;
    
    public class Client {
        public static void main(String[] args) throws Exception {
            String key = "";
            int n = -1;
            byte[] a = new byte[128];
            try {
                File f = new File("Ckey.dat");
                InputStream in = new FileInputStream(f);
                while ((n = in.read(a, 0, 100)) != -1) {
                    key = key + new String(a, 0, n);
                }
                in.close();
            } catch (IOException e) {
                System.out.println("File read Error" + e);
            }
            String mess;
            Scanner scanner = new Scanner(System.in);
            System.out.println("请输入问题为:");
            mess = scanner.nextLine();
            NewMyBC mybc = new NewMyBC();
            String str;
            mybc.setBeforeExpression(mess);
            str = mybc.transformWay();
            String md5 = DigestPass.md5(str);
            String mw = EncryptDecrypt.AESEncode(key, str);
            System.out.println("客户端提供的MD—5为:" + md5);
            System.out.println("客户加密之后的密文为:" + mw);
            Socket mysocket;
            DataInputStream in = null;
            DataOutputStream out = null;
            try {
                mysocket = new Socket("localhost", 2010);
                in = new DataInputStream(mysocket.getInputStream());
                out = new DataOutputStream(mysocket.getOutputStream());
                out.writeUTF(mw);
                out.writeUTF(md5);
                String answer = in.readUTF();   //in读取信息,堵塞状态
                System.out.println("客户收到服务器的回答为:" + answer);
                Thread.sleep(500);
            } catch (Exception e) {
                System.out.println("服务器已断开" + e);
            }
        }
    }
    
    

    部分代码,具体代码见码云链接

    二、实验截图:

    三、码云链接

    实验过程中遇到的问题及解决办法

    Q:在运行代码时,提示Error:(1, 1) java: 非法字符: 'ufeff',该怎么做?

    A:我百度了一下,找到了一篇博客,根据博客里的步骤,解决了问题。

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

    实验体会总结

    本次实验,我主要负责客户端代码,搭档负责服务器端代码,许多算法也是我们根据娄老师的博客共同研究出来的。本次实验是最后一次实验了,本学期的确受Java折磨不少,但是还是感谢娄老师给我们提供了很多新的学习方法,相信以后Java会帮助我们很多的。

  • 相关阅读:
    Treap 树堆 容易实现的平衡树
    (转)Maven实战(二)构建简单Maven项目
    (转)Maven实战(一)安装与配置
    根据请求头跳转判断Android&iOS
    (转)苹果消息推送服务器 php 证书生成
    (转)How to renew your Apple Push Notification Push SSL Certificate
    (转)How to build an Apple Push Notification provider server (tutorial)
    (转)pem, cer, p12 and the pains of iOS Push Notifications encryption
    (转)Apple Push Notification Services in iOS 6 Tutorial: Part 2/2
    (转)Apple Push Notification Services in iOS 6 Tutorial: Part 1/2
  • 原文地址:https://www.cnblogs.com/20165203-xyx/p/9101016.html
Copyright © 2011-2022 走看看