• 实验4


    学号 2019-2020-1 《数据结构与面向对象程序设计》实验4报告

    课程:《程序设计与数据结构》
    班级: 1823
    姓名: 郑力元
    学号:20182320
    实验教师:王志强
    实验日期:2019年10月4日
    必修/选修: 必修

    1.实验内容

    (一)Java Socket编程

    1.学习蓝墨云上教材《Java和Android编程》“第16章 输入/输出 ”和“第22章 网络”,学习JavaSocket编程
    2.结对编程。结对伙伴A编写客户端SocketClient.java,结对伙伴B编写服务器端。
    3.截图加学号水印上传蓝墨云,代码push到码云,并撰写实验报告。

    (二)Java和密码学

    参考 http://www.cnblogs.com/rocedu/p/6683948.html

    以结对的方式完成Java密码学相关内容的学习(帖子中所有代码和相关知识点需要学习)。提交学习成果码云链接和代表性成果截图,要有学号水印。

    (三)编写有理数/复数计算器

    结对编程,结对伙伴A编写有理数计算器。结对伙伴B编写复数计算器。截图加水印上传蓝墨云,代码push码云。

    (四)远程有理数计算器

    结对编程,结对伙伴A编程实现客户端,结果伙伴B实现服务器端。
    客户端通过键盘输入一个有理数计算的公式(例如:1/4 + 1/6 = ),并把该公式以字符串的形式发送给伙伴B(服务器端),服务器端根据字符串计算出结果为5/12,并把结果返回给客户端A,A收到结果后输出结果。截图加水印上传蓝墨云,代码push码云。

    (五)远程复数计算器

    结对编程,结对伙伴B编程实现客户端,结果伙伴A实现服务器端。
    客户端通过键盘输入一个有理数计算的公式(例如:1/4 + 1/6 = ),并把该公式以字符串的形式发送给伙伴A(服务器端),服务器端根据字符串计算出结果为5/12,并把结果返回给客户端B,B收到结果后输出结果。截图加水印上传蓝墨云,代码push码云。
    注意实验四(4)和实验四(5),一个人不能仅实现客户端,必须实现一个客户端和服务器,否则两个实验均不得分!!!

    (六)实验报告

    在规定时间前发表博客,标题“学号 实验四 《数据结构与面向对象程序设计》实验报告”

    2. 实验过程及结果

    实验4.1

    第一步:编写简单的服务器和终端

    代码老师已给出。

    第二步:在伙伴的电脑上运行服务器代码,在我的电脑上运行终端代码


    我将ip地址修改成伙伴电脑的之后,我的终端成功连接伙伴的服务器,并接收到反馈,如上。

    第三步:在我的电脑上运行服务器代码,在伙伴电脑上运行终端代码


    和第二步一样修改ip地址并实现连通后,出现账号和密码,如上。

    实验4.2

    要点:

    • 什么是密码学?

    答:主要是研究保密通信和信息保密的学科,包括信息保密传输和信息加密存储等。

    • 密码学的两大分支:

    密码编码学: 主要研究如何加密信息。

    密码分析学: 主要研究如何破译密码。

    编码学与分析学相互促进, 又相互制约。

    • 根据密钥的使用方法,将密码分为两种:

    对称密码(symmetric cryptography) 是指在加密和解密时使用同一密钥的方式。

    公钥密码(public-key cryptography) 则是指在加密和解密时使用不同密钥的方式,公钥密码又称为非对称密码(asymmetric cryptography)。

    • 密码与信息安全常识:

    不要使用保密的密码算法

    使用低强度的密码比不进行任何加密更危险

    任何密码总有一天都会被破解

    密码只是信息安全的一部分

    实验4.2.1:凯撒密码的加解密

    简介:

    凯撒密码的加密方法是,将明文的每个英文字母都向前(-x)或向后移动x位(+x),将明文加密成密文,这个x是密钥。

    第一步:编写代码(详解见下面注释)
    //首先,往这个方法中输入一个参数,类型是字符串型,赋给字符串数组args[]
    public static void main(String args[]) throws Exception{
            String s=args[0];//取输入的第一个字符串,即需要加密的明文
            int key=Integer.parseInt(args[1]);//取输入的第二个字符串,即密钥,并将其转为整型
            String es="";//创建接收密文的字符串变量并初始化
            for(int i=0;i<s.length( );i++)//一个个取明文的字符并逐一根据密钥进行加密
    {  char c=s.charAt(i);
                   if(c>='a' && c<='z') // 是小写字母
                      { c+=key%26;  //移动key%26位
                        if(c<'a') c+=26;  //向左超界
                        if(c>'z') c-=26;  //向右超界
                      }
                   else if(c>='A' && c<='Z') // 是大写字母
    {  c+=key%26;
                        if(c<'A') c+=26;
                        if(c>'Z') c-=26;
                      }
                   es+=c;
               }
           System.out.println(es);
         }
    
    第二步:运行代码并记录结果

    加密:

    解密:

    实验4.2.2 Java对称加密-DES算法

    第一步:编写生成密钥代码(详解见下面注释)
    方式1:创建密钥文件"key1.dat"并储存密钥对象
    import java.io.*;
    import javax.crypto.*;
    public class Skey_DES{ 
     public static void main(String args[])
     throws Exception{ 
     
    KeyGenerator kg=KeyGenerator.getInstance("DESede");
    //这一行是创建一个密钥生成器,指定使用"DESede"算法
    //与其它类的对象的创建方法不同,KeyGenerator通过它的静态方法getInstance()来创建对象
    
                kg.init(168); 
                //初始化密钥生成器kg
                
                SecretKey k=kg.generateKey( );
                //生成密钥。
                //Keygenerator类中的generateKey方法可以生成密钥,类型是SecretKey,可用于后面的加密解密
                
                FileOutputStream  f=new FileOutputStream("key1.dat");
                //创建一个FileOutputStream类f,同时创建并让f指向一个新文件"key1.dat"
                
                ObjectOutputStream b=new  ObjectOutputStream(f);
                //创建一个新的ObjectOutputStream类的对象
                
                b.writeObject(k);
                //将生成的密钥k序列化后保存在"key1.dat"文件中
             }
    }
    
    方式2:创建密钥文件"key1.dat"并以字节的方式储存密钥
    import java.io.*;
    import java.security.*;
    public class Skey_kb{
        public static void main(String args[]) throws Exception{
        
            FileInputStream f=new FileInputStream("key1.dat");
            ObjectInputStream b=new ObjectInputStream(f);
            //同上,生成密钥
            
            Key k=(Key)b.readObject( );
            //用readObject()读取密钥对象,并传入k中
            //因为readObject()返回的是Object类,所以要强制转换成Key类
            
            byte[ ] kb=k.getEncoded( );
            //创建一个byte类型的数组kb[],用Key的getEncoded()方法获取密钥编码格式
            
            FileOutputStream  f2=new FileOutputStream("keykb1.dat");
           f2.write(kb);
           //保存密钥编码格式到"keykb1.dat"文件中
           
            for(int i=0;i<kb.length;i++){
                     System.out.print(kb[i]+",");
            // 打印密钥编码中的内容
            }
       }
    }
    
    第二步:运行程序并生成"key1.dat"密钥文件
    方式1:

    方式2:

    第三步: 运用第一步第二步生成的密钥,编写加密器
    import java.io.*;
    import java.security.*;
    import javax.crypto.*;
    public class SEnc{
       public static void main(String args[]) throws Exception{
         
        FileInputStream f=new FileInputStream("key1.dat");
        ObjectInputStream b=new ObjectInputStream(f);
        Key k=(Key)b.readObject( );
        //从文件"key1.dat"中获取密钥
        
            Cipher cp=Cipher.getInstance("DESede");
            //创建一个密码器(Cipher类)对象,并指定加密算法"DESede"
            
            cp.init(Cipher.ENCRYPT_MODE, k);
            //初始化密码器
            
            String s="Hello World!";
            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);
            //将密文存入"SEnc.dat"文件
       }
    }
    
    第四步:运行加密器生成密文编码和密文文件


    将明文的编码以二进制写入文本文件,用文本编辑器打开,就能得到明文。

    第五步:使用密钥文件解密
    import java.io.*;
    import java.security.*;
    import javax.crypto.*;
    import javax.crypto.spec.*;
    public class SDec{
       public static void main(String args[]) throws Exception{
            
            FileInputStream f=new FileInputStream("SEnc.dat");
            int num=f.available();
            byte[ ] ctext=new byte[num];          
            f.read(ctext);
            // 获取密文
            
            FileInputStream  f2=new FileInputStream("keykb1.dat");
            int num2=f2.available();
            byte[ ] keykb=new byte[num2];          
            f2.read(keykb);
            SecretKeySpec k=new  SecretKeySpec(keykb,"DESede");
            // 获取密钥
            
            Cipher cp=Cipher.getInstance("DESede");
            cp.init(Cipher.DECRYPT_MODE, k);
            byte []ptext=cp.doFinal(ctext);
            // 解密
            
            String p=new String(ptext,"UTF8");
            System.out.println(p);
            // 显示明文
       }
    }
    
    第六步:运行解密代码解密密文

    实验4.2.3 Java非对称加密-RSA算法

    第一步:生成公钥和私钥
    import java.io.*;
    import java.security.*;
    import javax.crypto.*;
    import javax.crypto.spec.*;
    
    public class Skey_RSA{
       public static void main(String args[]) throws Exception{
            KeyPairGenerator kpg=KeyPairGenerator.getInstance("RSA");
            //创建密钥对生成器
            
            kpg.initialize(1024);
            //初始化密钥生成器
            
            KeyPair kp=kpg.genKeyPair();
            //生成密钥对
            
            PublicKey pbkey=kp.getPublic();
            PrivateKey prkey=kp.getPrivate();
            //生成公钥和私钥
            
            FileOutputStream  f1=new FileOutputStream("Skey_RSA_pub.dat");
            ObjectOutputStream b1=new  ObjectOutputStream(f1);
    b1.writeObject(pbkey);
            //保存公钥
            
            FileOutputStream  f2=new FileOutputStream("Skey_RSA_priv.dat");
            ObjectOutputStream b2=new  ObjectOutputStream(f2);
    b2.writeObject(prkey);
            //保存私钥
       }
    }
    

    第二步:利用公钥加密
    import java.security.*;
    import java.security.spec.*;
    import javax.crypto.*;
    import javax.crypto.spec.*;
    import javax.crypto.interfaces.*;
    import java.security.interfaces.*;
    import java.math.*;
    import java.io.*;
    public class Enc_RSA{
       public static void main(String args[]) throws Exception{
            String s="Hello World!";
            
            FileInputStream f=new FileInputStream("Skey_RSA_pub.dat");
            ObjectInputStream b=new ObjectInputStream(f);
            RSAPublicKey  pbk=(RSAPublicKey)b.readObject( );
            BigInteger e=pbk.getPublicExponent();
            BigInteger n=pbk.getModulus();
            System.out.println("e= "+e);
            System.out.println("n= "+n);
            // 获取公钥及参数e,n
            
            byte ptext[]=s.getBytes("UTF8");
            BigInteger m=new BigInteger(ptext);
            // 明文 m
            
            BigInteger c=m.modPow(e,n);
            System.out.println("c= "+c);
            // 计算密文c,打印
           
            String cs=c.toString( );
            BufferedWriter out= 
                 new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream("Enc_RSA.dat")));
            out.write(cs,0,cs.length( ));
            out.close( );
            // 保存密文
       }
    }
    

    第三步:用私钥解密
    import java.security.*;
    import java.security.spec.*;
    import javax.crypto.*;
    import javax.crypto.spec.*;
    import javax.crypto.interfaces.*;
    import java.security.interfaces.*;
    import java.math.*;
    import java.io.*;
    public class Dec_RSA{
       public static void main(String args[]) throws Exception{
           
            BufferedReader in= 
                    new BufferedReader(new InputStreamReader(
    new FileInputStream("Enc_RSA.dat")));
            String ctext=in.readLine();
            BigInteger c=new BigInteger(ctext);
            //读取密文
            
           
            FileInputStream f=new FileInputStream("Skey_RSA_priv.dat");
            ObjectInputStream b=new ObjectInputStream(f);
            RSAPrivateKey prk=(RSAPrivateKey)b.readObject( );
            BigInteger d=prk.getPrivateExponent();
            //读取私钥
            
            BigInteger n=prk.getModulus();
            System.out.println("d= "+d);
            System.out.println("n= "+n);
            BigInteger m=c.modPow(d,n);
            //获取私钥参数及解密
           
            System.out.println("m= "+m);
            byte[] mt=m.toByteArray();
            System.out.println("PlainText is ");
            for(int i=0;i<mt.length;i++){
                 System.out.print((char) mt[i]);
           }
           //显示解密结果
        }
    }
    

    实验4.2.4 使用密钥协定创建共享密钥

    第一步:创建DH公钥和私钥
    import java.io.*;
    import java.math.*;
    import java.security.*;
    import java.security.spec.*;
    import javax.crypto.*;
    import javax.crypto.spec.*;
    import javax.crypto.interfaces.*;
    
    public class Key_DH{
           
        private static final byte skip1024ModulusBytes[] = {
            (byte)0xF4, (byte)0x88, (byte)0xFD, (byte)0x58,
            (byte)0x4E, (byte)0x49, (byte)0xDB, (byte)0xCD,
            (byte)0x20, (byte)0xB4, (byte)0x9D, (byte)0xE4,
            (byte)0x91, (byte)0x07, (byte)0x36, (byte)0x6B,
            (byte)0x33, (byte)0x6C, (byte)0x38, (byte)0x0D,
            (byte)0x45, (byte)0x1D, (byte)0x0F, (byte)0x7C,
            (byte)0x88, (byte)0xB3, (byte)0x1C, (byte)0x7C,
            (byte)0x5B, (byte)0x2D, (byte)0x8E, (byte)0xF6,
            (byte)0xF3, (byte)0xC9, (byte)0x23, (byte)0xC0,
            (byte)0x43, (byte)0xF0, (byte)0xA5, (byte)0x5B,
            (byte)0x18, (byte)0x8D, (byte)0x8E, (byte)0xBB,
            (byte)0x55, (byte)0x8C, (byte)0xB8, (byte)0x5D,
            (byte)0x38, (byte)0xD3, (byte)0x34, (byte)0xFD,
            (byte)0x7C, (byte)0x17, (byte)0x57, (byte)0x43,
            (byte)0xA3, (byte)0x1D, (byte)0x18, (byte)0x6C,
            (byte)0xDE, (byte)0x33, (byte)0x21, (byte)0x2C,
            (byte)0xB5, (byte)0x2A, (byte)0xFF, (byte)0x3C,
            (byte)0xE1, (byte)0xB1, (byte)0x29, (byte)0x40,
            (byte)0x18, (byte)0x11, (byte)0x8D, (byte)0x7C,
            (byte)0x84, (byte)0xA7, (byte)0x0A, (byte)0x72,
            (byte)0xD6, (byte)0x86, (byte)0xC4, (byte)0x03,
            (byte)0x19, (byte)0xC8, (byte)0x07, (byte)0x29,
            (byte)0x7A, (byte)0xCA, (byte)0x95, (byte)0x0C,
            (byte)0xD9, (byte)0x96, (byte)0x9F, (byte)0xAB,
            (byte)0xD0, (byte)0x0A, (byte)0x50, (byte)0x9B,
            (byte)0x02, (byte)0x46, (byte)0xD3, (byte)0x08,
            (byte)0x3D, (byte)0x66, (byte)0xA4, (byte)0x5D,
            (byte)0x41, (byte)0x9F, (byte)0x9C, (byte)0x7C,
            (byte)0xBD, (byte)0x89, (byte)0x4B, (byte)0x22,
            (byte)0x19, (byte)0x26, (byte)0xBA, (byte)0xAB,
            (byte)0xA2, (byte)0x5E, (byte)0xC3, (byte)0x55,
            (byte)0xE9, (byte)0x2F, (byte)0x78, (byte)0xC7
        };
        //三个静态变量的定义从
        // C:j2sdk-1_4_0-docdocsguidesecurityjceJCERefGuide.html
        // 拷贝而来
        // The 1024 bit Diffie-Hellman modulus values used by SKIP
        
        
        private static final BigInteger skip1024Modulus
                  = new BigInteger(1, skip1024ModulusBytes);
        // The SKIP 1024 bit modulus
        
        private static final BigInteger skip1024Base = BigInteger.valueOf(2);
        // The base used with the SKIP 1024 bit modulus
        
    public static void main(String args[ ]) throws Exception{
        DHParameterSpec DHP=
    new DHParameterSpec(skip1024Modulus,skip1024Base);
    
         KeyPairGenerator kpg= KeyPairGenerator.getInstance("DH");
         kpg.initialize(DHP);
         KeyPair kp=kpg.genKeyPair();
    
         PublicKey pbk=kp.getPublic();
         PrivateKey prk=kp.getPrivate();
    
         FileOutputStream  f1=new FileOutputStream(args[0]);
         ObjectOutputStream b1=new  ObjectOutputStream(f1);
         b1.writeObject(pbk);
         // 保存公钥
    
         FileOutputStream  f2=new FileOutputStream(args[1]);
         ObjectOutputStream b2=new  ObjectOutputStream(f2);
         b2.writeObject(prk);
         // 保存私钥
       }      
    } 
    

    这里需要调整Program arguments参数,分别改为创建的两个文件的名字


    然后分别运行,产生公钥和私钥文件

    第二步:共享密钥

    编写

    import java.io.*;
    import java.math.*;
    import java.security.*;
    import java.security.spec.*;
    import javax.crypto.*;
    import javax.crypto.spec.*;
    import javax.crypto.interfaces.*;
    
    public class KeyAgree{
       public static void main(String args[ ]) throws Exception{
          
          FileInputStream f1=new FileInputStream(args[0]);
          ObjectInputStream b1=new ObjectInputStream(f1);
          PublicKey  pbk=(PublicKey)b1.readObject( );
          // 读取对方的DH公钥
    
          FileInputStream f2=new FileInputStream(args[1]);
          ObjectInputStream b2=new ObjectInputStream(f2);
          PrivateKey  prk=(PrivateKey)b2.readObject( );
         //读取自己的DH私钥
          
         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]+",");
         }
        SecretKeySpec k=new  SecretKeySpec(sb,"DESede");
        //生成共享信息
      }
    }  
    

    将这个代码分别复制到A和B的文件夹下,然后将Program arguments修改成“对方的公钥名+自己的私钥名”


    最后再运行并观察打印结果是否相等,若相等则共享成功

    实验4.2.5 Java摘要算法- MD5

    第一步:编写代码
    import java.security.*;
    public class DigestPass{
         public static void main(String args[ ]) throws Exception{
             String x=args[0];
             
             MessageDigest m=MessageDigest.getInstance("MD5");
             //生成对象并指定MD5算法
             
             m.update(x.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);
             }
             System.out.println(result);
          }   
    }
    
    第二步:修改Program arguments为需要加密的明文

    第三步:运行

    实验4.3 编写有理数/复数计算器

    实验4.3.1 编写有理数计算器

    第一步:编写分数类
    import java.util.StringTokenizer;
    
    public class Fraction {
        int fenzi,fenmu;
        char ch;
    
        public Fraction(String str) {
            StringTokenizer st=new StringTokenizer(str,"/",true);
            this.fenzi = Integer.parseInt(st.nextToken());
            this.ch=st.nextToken().charAt(0);
            this.fenmu = Integer.parseInt(st.nextToken());
        }
    
        public Fraction yuefen(int fz,int fm){
            int i;
    
            for (i=2;i<=fz&&i<=fm;i++){
                if(fz%i==0&&fm%i==0){
                    fz=fz/i;
                    fm=fm/i;
                }
            }
    
            Fraction result=new Fraction(fz+"/"+fm);
            return result;
        }
    
        public Fraction getJia(Fraction x){
            int newFenmu=fenmu*x.fenmu;
            int newFenzi=fenzi*x.fenmu+x.fenzi*fenmu;
            return yuefen(newFenzi,newFenmu);
        }
    
        public Fraction getJian(Fraction x){
            int newFenmu=fenmu*x.fenmu;
            int newFenzi=fenzi*x.fenmu-x.fenzi*fenmu;
            return yuefen(newFenzi,newFenmu);
        }
    
        public Fraction getCheng(Fraction x){
            int newFenmu=fenmu*x.fenmu;
            int newFenzi=fenzi*x.fenzi;
            return yuefen(newFenzi,newFenmu);
        }
    
        public Fraction getChu(Fraction x){
            int newFenmu=fenmu*x.fenzi;
            int newFenzi=fenzi*x.fenmu;
            return yuefen(newFenzi,newFenmu);
        }
    
        @Override
        public String toString() {
            return fenzi + "/" + fenmu;
        }
    }
    
        }
    }
    
    
    第二步:编写有理数计算器代码
    public class RationalNumberCalculator {
        public static void main(String[] args) {
    
            Fraction result;
            Fraction frac1,frac2;
            if(args[0].contains("/")){
                frac1=new Fraction(args[0]);
            }
            else{
                frac1=new Fraction(args[0]+"/"+1);
            }
    
            if(args[2].contains("/")){
                frac2=new Fraction(args[2]);
            }
            else{
                frac2=new Fraction(args[2]+"/"+1);
            }
    
            char ch=args[1].charAt(0);
    
    
            switch (ch)
            {
                case '+':
                    result=frac1.getJia(frac2);
                    System.out.println(frac1+String.valueOf(ch)+frac2+"="+result);
                    break;
                case '-':
                    result=frac1.getJian(frac2);
                    System.out.println(frac1+String.valueOf(ch)+frac2+"="+result);
                    break;
                case '*':
                    result=frac1.getCheng(frac2);
                    System.out.println(frac1+String.valueOf(ch)+frac2+"="+result);
                    break;
                case '/':
                    result=frac1.getChu(frac2);
                    System.out.println(frac1+String.valueOf(ch)+frac2+"="+result);
                    break;
                default:
                    System.out.println("Illegal input!");
                    break;
            }
        }
    }
    
    
    第三步:运行

    4.3.2 编写复数计算器

    第一步:编写复数类
    import java.util.StringTokenizer;
    
    public class Complex{
        private int RealPart;
        private int ImagePart;
        private char ch;
    
            //构造函数
            public Complex(){}
            public Complex(String str){
                StringTokenizer st=new StringTokenizer(str,".",true);
                this.RealPart=Integer.parseInt(st.nextToken());
                this.ch=st.nextToken().charAt(0);
                this.ImagePart=Integer.parseInt(st.nextToken());
            }
    
            //返回
            public double getRealPart(){
            return RealPart;
            }
    
            public double getImagePart(){
            return ImagePart;
            }
    
            //接收
            public void setRealPart(int realPart){
                RealPart=realPart;
            }
    
            public void setImagePart(int imagePart){
                ImagePart=imagePart;
            }
    
            //重写函数toString
            public String toString(){
                return RealPart + "." + ImagePart;
            }
    
            public boolean equals(Object a){
                if (a==this){
                    return true;
            }
                else{
                    return false;
            }
            }
    
            // 定义公有方法:加减乘除
            public Complex ComplexAdd(Complex a){
                Complex b = new Complex((this.RealPart+a.RealPart)+"."+(this.ImagePart+a.ImagePart));
                return b;
            }
            public Complex ComplexSub(Complex a){
                Complex b = new Complex((this.RealPart-a.RealPart)+"."+(this.ImagePart-a.ImagePart));
                return b;
            }
            public Complex ComplexMulti(Complex a){
                Complex b = new Complex((this.RealPart*a.RealPart-this.ImagePart*a.ImagePart)+"."+(this.ImagePart*a.RealPart+this.RealPart*a.ImagePart));
                return b;
            }
            public Complex ComplexDiv(Complex a){
                double scale = a.getRealPart()*a.getRealPart() + a.getImagePart()*a.getImagePart();
                Complex b = new Complex((a.getRealPart() / scale)+"."+
                        (- a.getImagePart() / scale));
                return b;
            }
    }
    
    第二步:编写复数计算器
    public class ComplexNumberCalculator{
        public static void main(String[] args) {
            Complex num1,num2,result;
    
            char ch=args[1].charAt(0);
    
            if(args[0].contains(".")){
                num1=new Complex(args[0]);
            }
            else{
                num1=new Complex(args[0]+"."+0);
            }
    
            if(args[2].contains(".")){
                num2=new Complex(args[2]);
            }
            else{
                num2=new Complex(args[2]+"."+0);
            }
    
            switch (ch)
            {
                case '+':
                    result=num1.ComplexAdd(num2);
                    System.out.println(num1+String.valueOf(ch)+num2+"="+result);
                    break;
                case '-':
                    result=num1.ComplexSub(num2);
                    System.out.println(num1+String.valueOf(ch)+num2+"="+result);
                    break;
                case '*':
                    result=num1.ComplexMulti(num2);
                    System.out.println(num1+String.valueOf(ch)+num2+"="+result);
                    break;
                case '/':
                    result=num1.ComplexDiv(num2);
                    System.out.println(num1+String.valueOf(ch)+num2+"="+result);
                    break;
                default:
                    System.out.println("Illegal input!");
                    break;
            }
        }
    }
    
    第三步:运行


    注:我在这里为了输入简便,将输入的实部和虚部用"."符号分隔。

    实验4.4 远程有理数计算器

    第一步:基于上面编写的分数类、计算器代码和之前老师给过的服务器和终端代码进行修改,得出如下代码:
    终端:
    import java.io.*;
    import java.net.Socket;
    
    /**
     * Created by besti on 2018/6/9.
     */
    public class SocketClient2 {
        public static void main(String[] args) throws IOException {
            //1.建立客户端Socket连接,指定服务器位置和端口
            Socket socket = new Socket("192.168.43.45",8809);
    //        Socket socket = new Socket("172.16.43.187",8800);
    
            //2.得到socket读写流
            OutputStream outputStream = socket.getOutputStream();
            //       PrintWriter printWriter = new PrintWriter(outputStream);
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
            //输入流
            InputStream inputStream = socket.getInputStream();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));
            //3.利用流按照一定的操作,对socket进行读写操作
            String info1 = " 1/4 + 1/6";
    //        String info = new String(info1.getBytes("GBK"),"utf-8");
            //     printWriter.write(info);
            //     printWriter.flush();
            outputStreamWriter.write(info1);
            outputStreamWriter.flush();
            socket.shutdownOutput();
            //接收服务器的响应
            String reply = null;
            while (!((reply = bufferedReader.readLine()) ==null)){
                System.out.println("接收服务器的信息为:" + reply);
            }
            //4.关闭资源
            bufferedReader.close();
            inputStream.close();
            outputStreamWriter.close();
            //printWriter.close();
            outputStream.close();
            socket.close();
        }
    }
    
    
    服务器:
    import java.io.*;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.StringTokenizer;
    
    /**
     * Created by besti on 2019/9/29.
     */
    public class Server18232 {
    
        private static Fraction frac2;
        private static Fraction frac1;
        private static String a,b;
        private static char ch;
        private static Fraction result = null;
    
        public static void main(String[] args) throws IOException {
            //1.建立一个服务器Socket(ServerSocket)绑定指定端口
            ServerSocket serverSocket=new ServerSocket(8809);
            //2.使用accept()方法阻止等待监听,获得新连接
            Socket socket=serverSocket.accept();
            //3.获得输入流
            InputStream inputStream=socket.getInputStream();
            BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream));
            //获得输出流
            OutputStream outputStream=socket.getOutputStream();
            PrintWriter printWriter=new PrintWriter(outputStream);
            //4.读取用户输入信息
            String info=null;
            System.out.println("服务器已经建立......");
            while(!((info = bufferedReader.readLine()) ==null)){
                System.out.println("我是服务器,用户信息为:" + info);
    
    
                StringTokenizer st = new StringTokenizer(info, " ", false);
                a=st.nextToken();
                ch=st.nextToken().charAt(0);
                b=st.nextToken();
                frac1=new Fraction(a);
                frac2=new Fraction(b);
    
                switch (ch)
                {
                    case '+':
                        result=frac1.getJia(frac2);
    
                        break;
                    case '-':
                        result=frac1.getJian(frac2);
    
                        break;
                    case '*':
                        result=frac1.getCheng(frac2);
    
                        break;
                    case '/':
                        result=frac1.getChu(frac2);
    
                        break;
                    default:
    
                        break;
                }
            }
    
    
    
    
            //给客户一个响应
            String reply=frac1+String.valueOf(ch)+frac2+"="+result;
            printWriter.write(reply);
            printWriter.flush();
            //5.关闭资源
            printWriter.close();
            outputStream.close();
            bufferedReader.close();
            inputStream.close();
            socket.close();
            serverSocket.close();
        }
    }
    
    
    
    第二步:修改参数后,先运行服务器后运行终端


    实验4.5 远程复数计算器

    第一步:基于上面编写的复数类、计算器代码和之前老师给过的服务器和终端代码进行修改,得出如下代码:
    终端:
    import java.io.*;
    import java.net.Socket;
    
    /**
     * Created by besti on 2018/6/9.
     */
    public class SocketClient3 {
        public static void main(String[] args) throws IOException {
            //1.建立客户端Socket连接,指定服务器位置和端口
            Socket socket = new Socket("192.168.43.45",8809);
    //        Socket socket = new Socket("172.16.43.187",8800);
    
            //2.得到socket读写流
            OutputStream outputStream = socket.getOutputStream();
            //       PrintWriter printWriter = new PrintWriter(outputStream);
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
            //输入流
            InputStream inputStream = socket.getInputStream();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));
            //3.利用流按照一定的操作,对socket进行读写操作
            String info1 = " 4.8 * 5.6";
    //        String info = new String(info1.getBytes("GBK"),"utf-8");
            //     printWriter.write(info);
            //     printWriter.flush();
            outputStreamWriter.write(info1);
            outputStreamWriter.flush();
            socket.shutdownOutput();
            //接收服务器的响应
            String reply = null;
            while (!((reply = bufferedReader.readLine()) ==null)){
                System.out.println("接收服务器的信息为:" + reply);
            }
            //4.关闭资源
            bufferedReader.close();
            inputStream.close();
            outputStreamWriter.close();
            //printWriter.close();
            outputStream.close();
            socket.close();
        }
    }
    
    
    服务器:
    import java.io.*;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.StringTokenizer;
    
    /**
     * Created by besti on 2019/9/29.
     */
    public class Server18233 {
    
        private static Complex cplx1;
        private static Complex cplx2;
        private static String a,b;
        private static char ch;
        private static Complex result = null;
    
        public static void main(String[] args) throws IOException {
            //1.建立一个服务器Socket(ServerSocket)绑定指定端口
            ServerSocket serverSocket=new ServerSocket(8809);
            //2.使用accept()方法阻止等待监听,获得新连接
            Socket socket=serverSocket.accept();
            //3.获得输入流
            InputStream inputStream=socket.getInputStream();
            BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream));
            //获得输出流
            OutputStream outputStream=socket.getOutputStream();
            PrintWriter printWriter=new PrintWriter(outputStream);
            //4.读取用户输入信息
            String info=null;
            System.out.println("服务器已经建立......");
            while(!((info = bufferedReader.readLine()) ==null)) {
                System.out.println("我是服务器,用户信息为:" + info);
    
    
                StringTokenizer st = new StringTokenizer(info, " ", false);
                a = st.nextToken();
                ch = st.nextToken().charAt(0);
                b = st.nextToken();
                cplx1 = new Complex(a);
                cplx2 = new Complex(b);
    
                switch (ch) {
                    case '+':
                        result = cplx1.ComplexAdd(cplx2);
    
                        break;
                    case '-':
                        result = cplx1.ComplexSub(cplx2);
    
                        break;
                    case '*':
                        result = cplx1.ComplexMulti(cplx2);
    
                        break;
                    case '/':
                        result = cplx1.ComplexDiv(cplx2);
                        break;
                    default:
                        break;
                }
            }
    
            //给客户一个响应
            String reply=cplx1+String.valueOf(ch)+cplx2+"="+result;
            printWriter.write(reply);
            printWriter.flush();
            //5.关闭资源
            printWriter.close();
            outputStream.close();
            bufferedReader.close();
            inputStream.close();
            socket.close();
            serverSocket.close();
        }
    }
    
    
    
    第二步:修改参数后,先运行服务器再运行终端


    3. 实验过程中遇到的问题和解决过程

    • 问题1:什么是密钥?
    • 问题1解决方案:

    百度百科:

    密钥是一个参数,在使用加密算法进行加密时,往里面输入的参数。

    • 问题2:搞不懂凯撒密码程序的下面这行代码的目的
    • 问题2解决方案:

    首先,明确key是密钥。

    其次,查找Integer.parseInt()方法的说明:

    最后,明确在主方法中只能输入字符串类型的参数,因此需要上面这行代码将输入的密钥转化成整型变量,以用于后面的加解密计算。

    • 问题3:FileInputStream和FileOutputStream的用法?
    • 问题3解决方案:

    CSDN:


    可见分别是用来读取文件中的数据和生成文件的。

    • 问题4:在System.out.println()中想要打印字符型,但是却打印出了它的ASCII码值。

    • 问题4解决方案:使用String.valueOf('字符')的方法,就能将字符型以字符串形式返回。

    • 问题5:计算器无法实现分数的计算

    • 问题5解决方案:自己编写一个分数类

    其他(感悟、思考等)

    作业看似不多,但是通往成功的路上充满了坎坷。特别是报出几行错之后开始肉眼调试,我太难了。

    参考资料

  • 相关阅读:
    Thymeleaf 异常:Exception processing template "index": An error happened during template parsing (template: "class path resource [templates/index.html]")
    Java 异常 Failed to convert property value of type 'java.lang.String' to required type 'java.util.Date'
    MySQL 查询字段时,区分大小写
    Oracle Database XE 11gR2 SQL 命令行的显示调整
    使用 PL/SQL Developer 导入 .sql 文件
    下载、安装 PL/SQL Developer
    安装、验证安装 Oracle Database XE 11gR2
    下载 Oracle Database XE 11gR2
    MyEclipse 设置打开 jsp 文件的默认编辑器
    Oracle Database XE 11gR2 自带的用户,新建用户,修改用户密码
  • 原文地址:https://www.cnblogs.com/leonzheng/p/11631725.html
Copyright © 2020-2023  润新知