20202302 《数据结构与面向对象程序设计》实验四报告
课程:《程序设计与数据结构》
班级: 2023
姓名:吉相融
学号:20202302
实验教师:王志强
实验日期:2021年10月22日
必修/选修: 必修
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.实验过程及结果
本次实验我(20202302)与张焘同学(20202329)组队完成
实验4.1 Java Socket编程
4.1.1 编写服务器
import java.io.*; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) throws IOException { //建立服务器绑定窗口 ServerSocket serverSocket = new ServerSocket(8800); //accept()方法处理连接请求,防止非法监听 Socket socket = serverSocket.accept(); //输入流 InputStream inputStream = socket.getInputStream(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); //输出流 OutputStream outputStream = socket.getOutputStream(); PrintWriter printWriter = new PrintWriter(outputStream); //读取用户信息 String info = null; System.out.println("服务器正在建立......"); //反馈信息 while (!((info = bufferedReader.readLine()) == null )) { System.out.println("我是服务器Ji,接受的信息为:" + info); } String reply = "Hello 2023!"; //传递信息 printWriter.write(reply); printWriter.flush(); //关闭资源 inputStream.close(); outputStream.close(); bufferedReader.close(); printWriter.close(); serverSocket.close(); socket.close(); } }
4.1.2 编写客户端(由20202329张焘编写)
import java.io.* ; import java.net.Socket ; public class Client { public static void main(String[] args) throws IOException { //建立客户端连接 Socket socket=new Socket("192.168.43.11",8800); //输出流,得到socket读写流 OutputStream outputStream =socket.getOutputStream(); OutputStreamWriter outputStreamWriter =new OutputStreamWriter(outputStream ); InputStream inputStream =socket .getInputStream() ; BufferedReader bufferedReader =new BufferedReader(new InputStreamReader(inputStream ,"UTF-8") ); String info="用户名:jxr 密码:20202302"; outputStreamWriter.write(info); outputStreamWriter.flush(); socket.shutdownOutput() ; //接受响应 String reply=null; while(!((reply= bufferedReader.readLine())==null)){ System.out.println(reply); } //关闭资源 bufferedReader .close(); inputStream.close(); outputStream .close(); socket.close(); } }
实验4.2 Java和密码学
相关内容:
开发一个程序时,最好的方法就是将对象想象为“服务提供者”,程序通过调用若干对象提供的服务来实现预期目标。
密码学: 主要是研究保密通信和信息保密的学科, 包括信息保密传输和信息加密存储等。
密码编码学: 主要研究如何对信息进行编码, 如何实现对信息的隐蔽, 是密码学理论的基础, 也是保密系统设计的基础。
密码分析学: 主要研究加密消息的破译或消息的伪造, 是检验密码体制安全性最为直接的手段, 只有通过实际密码分析考验的密码体制,才是真正可用的。
对称密码(symmetric cryptography)是指在加密和解密时使用同一密钥的方式。
公钥密码(public-key cryptography)则是指在加密和解密时使用不同密钥的方式,公钥密码又称为非对称密码(asymmetric cryptography)。
4.2.1 凯撒密码
凯撒密码的加密算法极其简单。其加密过程如下:
我们做此约定:明文记为m,密文记为c,加密变换记为E(k1,m)(其中k1为密钥),解密变换记为D(k2,m)(k2为解密密钥)(在这里k1=k2,不妨记为k)。凯撒密码的加密过程可记为如下一个变换:
c≡m+k mod n (其中n为基本字符个数)
同样,解密过程可表示为:
m≡c+k mod n (其中n为基本字符个数)
代码:
public class Caesar { //凯撒密码加密 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算法
法一:将密钥通过对象序列化方式保存在文件中
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); //将生成的密钥k序列化后保存在"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]+","); // 打印密钥编码中的内容 } } }
编写加密器,生成密文编码和密文文件
import java.io.*; import java.security.*; import javax.crypto.*; import javax.crypto.spec.SecretKeySpec; public class SEnc { public static void main(String[] args) throws Exception{ File file; FileInputStream f = new FileInputStream("key1.dat"); ObjectInputStream b = new ObjectInputStream(f); Key k = (Key)b.readObject(); Cipher cp = Cipher.getInstance("DESede"); cp.init(Cipher.ENCRYPT_MODE,k); String s = "Hello 2023"; byte ptext[] = s.getBytes("UTF8"); for(int i = 0;i<ptext.length;i++) { System.out.println(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); } }
使用密钥文件解密
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); } }
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{ //当前目录下将生成两个文件:Skey_RSA_pub.dat和Skey_RSA_priv.dat,前者保存着公钥,后者保存着私钥。 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.io.*; import java.security.*; import javax.crypto.*; import javax.crypto.spec.*; public class Skey_RSA{ //当前目录下将生成两个文件:Skey_RSA_pub.dat和Skey_RSA_priv.dat,前者保存着公钥,后者保存着私钥。 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); byte ptext[]=s.getBytes("UTF8"); BigInteger m=new BigInteger(ptext); BigInteger c=m.modPow(e,n); System.out.println("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 使用密钥协定创建共享密钥
建立两个目录A和B,模拟需要秘密通信的A、B双方,由于DH算法需要A和B各自生成DH公钥和私钥,因此在这两个目录下都拷贝编译后文件Key_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 }; 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); } }
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_B{ 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 }; 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); } }
创建共享密钥
需要在AB两个目录下都复制粘贴编译代码
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( ); FileInputStream f2=new FileInputStream(args[1]); 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]+","); } SecretKeySpec k=new SecretKeySpec(sb,"DESede"); } }
将命令行参数修改成“对方的公钥名+自己的私钥名”
打印结果相同,共享成功!!!!!!!
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); } }
将参数调整为需要加密的明文
加密完成!!!!!1
4.3 编写有理数/复数计算器
4.1.1 20202329张焘的有理数计算器
public class RationalNumberCalculator { public static void main(String[] args) { fenshu result; fenshu fenshu1,fenshu2; if(args[0].contains("/")){ fenshu1=new fenshu(args[0]); } else{ fenshu1=new fenshu(args[0]+"/"+1); } if(args[2].contains("/")){ fenshu2=new fenshu(args[2]); } else{ fenshu2=new fenshu(args[2]+"/"+1); } char ch=args[1].charAt(0); switch (ch) { case '+': result=fenshu1.getJia(fenshu2); System.out.println(fenshu1+String.valueOf(ch)+fenshu2+"="+result); break; case '-': result=fenshu1.getJian(fenshu2); System.out.println(fenshu1+String.valueOf(ch)+fenshu2+"="+result); break; case '*': result=fenshu1.getCheng(fenshu2); System.out.println(fenshu1+String.valueOf(ch)+fenshu2+"="+result); break; case '/': result=fenshu1.getChu(fenshu2); System.out.println(fenshu1+String.valueOf(ch)+fenshu2+"="+result); break; default: System.out.println("Illegal input!"); break; } } }
import java.util.StringTokenizer; public class fenshu { int fenzi,fenmu; char ch; public fenshu(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 fenshu 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; } } fenshu result=new fenshu(fz+"/"+fm); return result; } public fenshu getJia(fenshu x){ int newFenmu=this.fenmu*x.fenmu; int newFenzi=fenzi*x.fenmu+x.fenzi*fenmu; return yuefen(newFenzi,newFenmu); } public fenshu getJian(fenshu x){ int newFenmu=fenmu*x.fenmu; int newFenzi=fenzi*x.fenmu-x.fenzi*fenmu; return yuefen(newFenzi,newFenmu); } public fenshu getCheng(fenshu x){ int newFenmu=fenmu*x.fenmu; int newFenzi=fenzi*x.fenzi; return yuefen(newFenzi,newFenmu); } public fenshu getChu(fenshu x){ int newFenmu=fenmu*x.fenzi; int newFenzi=fenzi*x.fenmu; return yuefen(newFenzi,newFenmu); } @Override public String toString() { return fenzi + "/" + fenmu; } }
4.3.2 复数计算器
import java.io.Reader; import java.util.*; public class Calculator { static double a,b,c,d; double RealPart; double ImagePart; static String choose; public static char ch; public void Add() { RealPart = a + c; ImagePart = b + d; } public void Sub() { RealPart = a - c; ImagePart = b - d; } public void Mul() { RealPart = a * c - b * d; ImagePart = b * c + a * d; } public void Div() { RealPart = (a * c - b * d) / (c * c + d * d); ImagePart = ( b * c + a * d ) / (c * c + d * d); } public String toSring(String s){ if(ImagePart >= 0){ return s + "=" + RealPart + "+" +ImagePart + "i"; } else { return s + "=" + RealPart + "" + ImagePart + "i"; } } public void Faction(String f){ char z; StringTokenizer st = new StringTokenizer(f, " ", false); z = st.nextToken().charAt(0); a = Double.parseDouble(st.nextToken()); z = st.nextToken().charAt(0); b = Double.parseDouble(st.nextToken()); z = st.nextToken().charAt(0); z = st.nextToken().charAt(0); ch = st.nextToken().charAt(0); z = st.nextToken().charAt(0); c = Double.parseDouble(st.nextToken()); z = st.nextToken().charAt(0); d = Double.parseDouble(st.nextToken()); } }
import java.util.Scanner; public class Plural extends Calculator { public static void main(String[] args) { String next = "y"; String s; do { Scanner scan = new Scanner(System.in); System.out.println("请输入复数计算式,各符号数字间用空格隔开,负数除外(如:( 1 + 2 i ) + ( 2 + -3 i ) ):"); Calculator ff; ff = new Plural(); s = scan.nextLine(); ff.Faction(s); Calculator count; count = new Plural(); switch (ch) { case '+': { count.Add(); break; } case '-': { count.Sub(); break; } case '*': { count.Mul(); break; } case '/': { count.Div(); break; } default: System.out.println("Illegal input!"); break; } System.out.println(count.toSring(s)); System.out.println("如果想要继续计算,请输入y,否则输入任意符号: "); choose = scan.nextLine(); }while (choose.equals(next)); } }
import java.util.Scanner; public class Plural extends Calculator { public static void main(String[] args) { String next = "y"; String s; do { Scanner scan = new Scanner(System.in); System.out.println("请输入复数计算式,各符号数字间用空格隔开,负数除外(如:( 1 + 2 i ) + ( 2 + -3 i ) ):"); Calculator ff; ff = new Plural(); s = scan.nextLine(); ff.Faction(s); Calculator count; count = new Plural(); switch (ch) { case '+': { count.Add(); break; } case '-': { count.Sub(); break; } case '*': { count.Mul(); break; } case '/': { count.Div(); break; } default: System.out.println("Illegal input!"); break; } System.out.println(count.toSring(s)); System.out.println("如果想要继续计算,请输入y,否则输入任意符号: "); choose = scan.nextLine(); }while (choose.equals(next)); } }
4.4 远程有理数计算器
20202329张焘客户端
import java.io.*; import java.net.Socket; public class Client2Rational { public static void main(String[] args) throws IOException { //建立客户端连接 Socket socket = new Socket("192.168.43.11", 2302); //输出流,得到socket读写流 OutputStream outputStream = socket.getOutputStream(); OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream); //输入流 InputStream inputStream = socket.getInputStream(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); //对Socket进行读写操作 String infol = "1/4+1/6"; String z = infol; String test = ""; int h = 4; for (int j = 0; j < z.length(); j++) { char k = z.charAt(j); if (k > 0 && k <= 127) { k += h % 26; if (k < 0) k += 127; if (k > 127) k -= 127; } test += k; } outputStreamWriter.write(test); outputStreamWriter.flush(); socket.shutdownOutput(); //接受响应 String reply = null; while (!((reply = bufferedReader.readLine()) == null)) { System.out.println(reply); String s = reply; String es = ""; h = -4; for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (c >= 0 && c <= 127) { c += h % 26; if (c < 0) c += 127; if (c > 0) c -= 127; } es += c; } System.out.println("es"); } //关闭资源 bufferedReader.close(); inputStream.close(); outputStreamWriter.close(); outputStream.close(); socket.close(); } }
服务器
import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.util.StringTokenizer; public class Server2 { private static fenshu frac2; private static fenshu frac1; private static String a,b; private static char ch; private static fenshu result = null; public static void main(String[] args) throws IOException { //1.建立一个服务器Socket(ServerSocket)绑定指定端口 ServerSocket serverSocket=new ServerSocket(8808); //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); String s= info; String es=""; int key = -4; for(int i=0;i<s.length( );i++) { char c=s.charAt(i); if(c>=0 && c<=127) // 是小写字母 { c+=key%26; //移动key%26位 if(c<0) c+=127; //向左超界 if(c>127) c-=127; //向右超界 } es+=c; } System.out.println("我是服务器,用户的解密后的信息为:" + es); StringTokenizer st = new StringTokenizer(es, " ", false); a=st.nextToken(); ch=st.nextToken().charAt(0); b=st.nextToken(); frac1=new fenshu(a); frac2=new fenshu(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; String z= reply; String tes=""; int key = 4; for(int j=0;j<z.length( );j++) { char d=z.charAt(j); if(d>=0 && d<=127) // 是小写字母 { d+=key%26; //移动key%26位 if(d<0) d+=127; //向左超界 if(d>127) d-=127; //向右超界 } tes+=d; } printWriter.write(tes); printWriter.flush(); //5.关闭资源 printWriter.close(); outputStream.close(); bufferedReader.close(); inputStream.close(); socket.close(); serverSocket.close(); } }
我的服务器以及张焘的客户端的运行结果
4.5远程复数计算器
我的客户端
import java.io.*; import java.net.Socket; public class Client1 { public static void main(String[] args) throws IOException { Socket socket = new Socket("192.168.43.11",8800); InputStream inputStream = socket.getInputStream(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"UTF-8")); OutputStream outputStream = socket.getOutputStream(); OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream); String s= "( 1 + 2 i ) + ( 1 + -2 i )"; int key=4; String es=""; for(int i=0;i<s.length( );i++){ char c=s.charAt(i); if(c>='a' && c<='z') { c+=key%26; if(c<'a') c+=26; //向左超界 if(c>'z') c-=26; //向右超界 } else if(c>='0' && c<='9') // 是数字 { c+=key%10; if(c<'0') c+=10; if(c>'9') c-=10; } else if(c>='*' && c<='/') { c+=key%6; if(c<'*') c+=6; if(c>'/') c-=6; } es+=c; } System.out.println(es); String info1 = es; outputStreamWriter.write(info1); outputStreamWriter.flush(); socket.shutdownOutput(); //接受响应 String reply = null; while (!((reply = bufferedReader.readLine())==null)){ System.out.println(reply); } bufferedReader.close(); inputStream.close(); outputStreamWriter.close(); outputStream.close(); } }
import java.io.*; import java.net.Socket; public class Client1 { public static void main(String[] args) throws IOException { Socket socket = new Socket("192.168.43.11",8800); InputStream inputStream = socket.getInputStream(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"UTF-8")); OutputStream outputStream = socket.getOutputStream(); OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream); String s= "( 1 + 2 i ) + ( 1 + -2 i )"; int key=4; String es=""; for(int i=0;i<s.length( );i++){ char c=s.charAt(i); if(c>='a' && c<='z') { c+=key%26; if(c<'a') c+=26; //向左超界 if(c>'z') c-=26; //向右超界 } else if(c>='0' && c<='9') // 是数字 { c+=key%10; if(c<'0') c+=10; if(c>'9') c-=10; } else if(c>='*' && c<='/') { c+=key%6; if(c<'*') c+=6; if(c>'/') c-=6; } es+=c; } System.out.println(es); String info1 = es; outputStreamWriter.write(info1); outputStreamWriter.flush(); socket.shutdownOutput(); //接受响应 String reply = null; while (!((reply = bufferedReader.readLine())==null)){ System.out.println(reply); } bufferedReader.close(); inputStream.close(); outputStreamWriter.close(); outputStream.close(); } }
张焘的服务器
import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.util.StringTokenizer; public class Server2 { private static fenshu frac2; private static fenshu frac1; private static String a,b; private static char ch; private static fenshu result = null; public static void main(String[] args) throws IOException { //1.建立一个服务器Socket(ServerSocket)绑定指定端口 ServerSocket serverSocket=new ServerSocket(8808); //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); String s= info; String es=""; int key = -4; for(int i=0;i<s.length( );i++) { char c=s.charAt(i); if(c>=0 && c<=127) // 是小写字母 { c+=key%26; //移动key%26位 if(c<0) c+=127; //向左超界 if(c>127) c-=127; //向右超界 } es+=c; } System.out.println("我是服务器,用户的解密后的信息为:" + es); StringTokenizer st = new StringTokenizer(es, " ", false); a=st.nextToken(); ch=st.nextToken().charAt(0); b=st.nextToken(); frac1=new fenshu(a); frac2=new fenshu(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; String z= reply; String tes=""; int key = 4; for(int j=0;j<z.length( );j++) { char d=z.charAt(j); if(d>=0 && d<=127) // 是小写字母 { d+=key%26; //移动key%26位 if(d<0) d+=127; //向左超界 if(d>127) d-=127; //向右超界 } tes+=d; } printWriter.write(tes); printWriter.flush(); //5.关闭资源 printWriter.close(); outputStream.close(); bufferedReader.close(); inputStream.close(); socket.close(); serverSocket.close(); } }
运行结果:
张焘的服务器与我的客户端
3. 实验过程中遇到的问题和解决过程
1.我的服务器与搭档的客户端无法连接
解决方法:第一步,要先保证两个人连接的是同一个热点,最好使用个人热点(因为后面要关闭防火墙。)
第二步,在设置中将两个人的全部防火墙关闭。
第三步,在网络设置中找到服务器的IP地址,在客户端对应位置输入。先运行服务器,再运行客户端,即可连接成功。
2.服务器与客户端连接成功时会由于解凯撒密码而报错。
此处要保证两个人的凯撒密码加密解密程序要一致,我们两人第一次连接时由于两个人的关于凯撒密码的程序有出入,导致无法正常连接。
4.感悟与思考
这次实验量真的有亿亿亿亿亿亿点点多,尤其是关于密码学相关部分,感觉人都要不对了。不过本次实验有了与搭档的交互,费劲千辛万苦连接成功的那一刻感觉非常开心!
不过本次实验关于密码学的部分还是没能掌握,只是熟悉了一遍相关代码。服务器客户端的建立还有待提升熟练度。
不说了,,,我要奖励自己一下!