20175316 盛茂淞 2018-2019-2 《Java程序设计》实验五 《网络安全与编程》 实验报告

一、实验报告封面

课程:Java程序设计 班级:1753班 姓名:盛茂淞 学号:20175316

指导教师:娄嘉鹏 实验日期:2018年5月31日

实验时间:15:35 - 17:15 实验序号:五

实验名称: 网络编程与安全

实验目的:

1、掌握Java Socket的相关内容;

2、学会建立客户端与服务器端之间的联系;

3、学习并应用密码学的相关内容

二、实验内容

任务(一)

  • 1、结对实现中缀表达式转后缀表达式的功能 MyBC.java
  • 2、结对实现从上面功能中获取的表达式中实现后缀表达式求值的功能,调用MyDC.java

任务(二)

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

任务(三)

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

任务(四)

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

任务(五)

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

    最后将每个任务的代码上传到码云。

三、实验步骤

任务(一)

  • 任务(一)早在结队编程—四则运算中我们就已经实现了中缀转后缀的功能,以及将后缀表达式利用栈进行运算的功能。因此任务(一)我们直接在之前代码的基础上进行修改即可。

  • 具体方法:

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

    OP + S1 + S2 为前缀表示法

    S1 + OP + S2 为中缀表示法

    S1 + S2 + OP 为后缀表示法

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

  • 设立一个栈,存放运算符,首先栈为空;

  • 从左到右扫描中缀式,若遇到操作数,直接输出,并输出一个空格作为两个操作数的分隔符;

  • 若遇到运算符,则与栈顶比较,比栈顶级别高则进栈,否则退出栈顶元素并输出,然后输出一个空格作分隔符;

  • 若遇到左括号,进栈;若遇到右括号,则一直退栈输出,直到退到左括号止。

  • 当栈变成空时,输出的结果即为后缀表达式。

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

  • 设置一个操作数栈,开始栈为空;

  • 从左到右扫描后缀表达式,遇操作数,进栈;

  • 若遇运算符,则从栈中退出两个元素,先退出的放到运算符的右边,后退出的放到运算符左边,运算后的结果再进栈,直到后缀表达式扫描完毕。

  • 此时,栈中仅有一个元素,即为运算的结果。

  • 中缀转后缀代码

import java.util.*;
import java.lang.*;
public class MyBC{
String Normal;
String Behind= ""; //后序表示
int countLeft=0,countRight=0;
public void setNormal(String str){
Normal=str;
Behind="";
}
public void change(){
Stack stack=new Stack();
int opValue []=new int[100];
for (int i=0;i<Normal.length() ;i++) {
char chi=Normal.charAt(i);
if (chi>='0'&&chi<='9'){ //数字直接输出
Behind=Behind+chi;
}
else if (chi=='+'||chi=='-'||chi=='*'||chi=='÷'||chi=='/') { //如果是运算符的话:
Behind=Behind+" ";
if (stack.empty()){ //若栈为空,入栈
stack.push(chi);
}
else if (Value(chi)>Value((char)stack.peek())) { //若栈不空,那么比较优先级,如果优先级比栈顶元素高,入栈
stack.push(chi);
}
else{
Behind=Behind+ String.valueOf(stack.pop())+" ";//否则出栈输出
i--;
}
}
else if(chi=='('){
countLeft++;
stack.push(chi);//左括号直接压栈
}
else if(chi==')'){ //如果遇到右括号,不停出栈并输出直到遇到左括号,把左括号出栈
Behind+=" ";
countRight++;
while((char)stack.peek()!='('){
Behind=Behind+ String.valueOf(stack.pop())+" ";
}
stack.pop();
}
}
Behind+=" ";
while(!stack.empty()){
Behind=Behind+String.valueOf(stack.pop())+" ";
}
}
public int Value(char c){ //设定不同运算符的优先级
int value=0;
switch(c){
case '(':
value=1;
break;
case '+':
case '-':
value=2;
break;
case '*':
case '÷':
value=3;
break;
case '/':
value=4;
break;
case ')':
value=5;
default:
value=0;
}
return value;
}
}
  • 求后缀表达式
import java.util.*;

public class Caculate {
public String caculate(String r){
Rational result=new Rational();
OutOfStack calculate=new OutOfStack();
result=calculate.evaluate(r); //运算出结果
int a=result.getNumerator();//获得结果的分子
int b=result.getDenominator();//获得结果的分母
if (b==1){
return String.valueOf(a);
}
else{
return String.valueOf(a)+"/"+String.valueOf(b);
} }
}

代码运行结果如下,可以多种符号的四则运算。

任务(二)

通过java.net包中的Socket类和ServerSocket类来实现这个功能

  • 套接字:IP地址表示计算机,端口号表示进程(线程),Socket类创建套接字对象并连接在一起(端口号与IP地址组合)。

  • 客户端程序用Socket类创建负责连接到服务器的套接字对象,其构造方法为Socket([IP地址],[端口号])(可能抛出IOException异常)。对套接字对象建立后,可以使用

    ①getInputStream()获得一个输入流来读取服务器写入到输出流中的数据;②getOutputStream()获得一个输出流,服务器可以用输入流来读取客户写入到输出流中的数据。

  • 客户负责建立连接到服务器的套接字对象。服务器需要创建一个ServerSocket对象来将客户端的套接字对象与服务器的套接字对象连接起来。ServerSocket的构造方法是ServerSocket([端口号])(当端口已被占用会抛出IOException异常)。接着,ServerSocket对象调用accept()方法再次返回一个与客户端对象相连接的新的Socket对象。同样的,它也具有上述的两个方法。

  • 从套接字连接中读取数据,可能在另一端数据发送之前就已经开始读取了,而且会阻塞本线程,直到成功读取到信息。同时,accept方法也会阻塞线程的执行,直到收到客户的呼叫。为了解决“收不到呼叫而导致程序无法继续运行”的情况,ServerSocket对象在调用accept方法之前可以先调用setTimeout(s)方法来使得在调用accept方法时如果超过s毫秒没有收到呼叫,就抛出SocketTimeoutException异常。

  • 双方通信完毕,套接字要使用close()方法关闭套接字连接。

  • 使用多线程技术:由于使用套接字连接中读取数据时,可能会阻塞本线程直到成功读取到信息。为了避免这种情况,需要启动一个专门为该客户服务的线程。Socket的构造方法Socket()可以创建一个套接字对象,该对象调用public void connect(SocketAddress endpoint) throws IOException来与指定的套接字创建连接。这里的参数可以使用InetSocketAddress的构造方法public InetSocketAdress(InetAdress addr,int port)来获得。套接字通信的两个基本原则:

    ①服务器要启动一个专门的线程与客户的套接字建立连接;

    ②套接字的输入流在读取信息时可能发生阻塞,所以客户端与服务器端都需要在一个单独的线程中读取信息。

  • 客户端关键代码

    System.out.print("输入中缀表达式:");
while(scanner.hasNext()) {
String middle="";//初始化middle
try {
middle = scanner.next();//输入中缀表达式
}
catch(InputMismatchException exp){
System.exit(0);
}
try {
myBC.setNormal(middle);
myBC.change();//调用M有BC中的类来将中缀表达式转化为后缀表达式。
System.out.println("后缀表达式:"+myBC.Behind); //Behind是类变量,所以可以通过类名来调用。
out.writeUTF(myBC.Behind);//将后缀表达式写进流中 }
catch(Exception e) {}
}
  • Read类输出结果
...
public void run() {
String result="";
while(true) {
try{ result=in.readUTF();//读取从服务器端传输回来的结果
System.out.println("结果:"+result);
System.out.println("输入中缀表达式:");//可以再次输入新的表达式进行运算。
}
catch(IOException e) {
System.out.println("与服务器已断开"+e);
break;
}
}
}
...
  • 服务器端关键代码
 ...
@Override
public void run() {
while(true) {
try{ String r=in.readUTF();//堵塞状态,除非读取到信息
String result=caculate.caculate(r);//调用Caculate类进行运算
out.writeUTF(result);//将结果写入到流中
}
catch (IOException e) {
System.out.println("客户离开");
return;
}
}
}
...
  • 运行代码
  • 客户端截图

  • 服务器端截图

任务(三)

  • 参考了之前实验三时娄老师的博客:Java 密码学算法,使用了DES算法。
  • 加密部分代码
...
String cipher=sEnc.Cipher(myBC.Behind);//将后缀表达式加密
out.writeUTF(cipher);//将加密结果写入到流中让服务器端读取
...
  • 解密部分代码
...
String r=in.readUTF();//读取客户端传过来的密文
String plain=sDec.Plain(r);//解密
String result=caculate.caculate(plain);//将解密得到的后缀表达式进行计算,然后返回计算结果。
...
  • 运行截图

    客户端



    服务器端

任务(四)

关于DH算法

  • Diffie-Hellman是一种建立密钥的方法,而不是加密方法。然而,它所产生的密钥可用于加密、进一步的密钥管理或任何其它的加密方式。
  • 基于原根的定义及性质,可以定义Diffie-Hellman密钥交换算法.该算法描述如下:

    1,有两个全局公开的参数,一个素数q和一个整数a,a是q的一个原根.

    2,假设用户A和B希望交换一个密钥,用户A选择一个作为私有密钥的随机数XA(XA<q),并计算公开密钥YA=a^XA mod q。A对XA的值保密存放而使YA能被B公开获得。类似地,用户B选择一个私有的随机数XB<q,并计算公开密钥YB=a^XB mod q。B对XB的值保密存放而使YB能被A公开获得。

    3,用户A产生共享秘密密钥的计算方式是K = (YB)^XA mod q.同样,用户B产生共享秘密密钥的计算是K = (YA)^XB mod q.这两个计算产生相同的结果: K = (YB)^XA mod q = (a^XB mod q)^XA mod q = (aXB)XA mod q (根据取模运算规则得到) = a^(XBXA) mod q = (aXA)XB mod q = (a^XA mod q)^XB mod q = (YA)^XB mod q 因此相当于双方已经交换了一个相同的秘密密钥.

    4,因为XA和XB是保密的,一个敌对方可以利用的参数只有q,a,YA和YB.因而敌对方被迫取离散对数来确定密钥.例如,要获取用户B的秘密密钥,敌对方必须先计算 XB = inda,q(YB) 然后再使用用户B采用的同样方法计算其秘密密钥K. Diffie-Hellman密钥交换算法的安全性依赖于这样一个事实:虽然计算以一个素数为模的指数相对容易,但计算离散对数却很困难.对于大的素数,计算出离散对数几乎是不可能的. 下面给出例子.密钥交换基于素数q = 97和97的一个原根a = 5.A和B分别选择私有密钥XA = 36和XB = 58.每人计算其公开密钥 YA = 5^36 = 50 mod 97 YB = 5^58 = 44 mod 97 在他们相互获取了公开密钥之后,各自通过计算得到双方共享的秘密密钥如下: K = (YB)^XA mod 97 = 44^36 = 75 mod 97 K = (YA)^XB mod 97 = 50^58 = 75 mod 97 从|50,44|出发,攻击者要计算出75很不容易。

客户端运行截图



服务器端运行截图

任务(五)

  • 在任务(四)的基础上引入MD5算法加密的类,调用其他的函数,参数为要加密的字符串,返回加密后的字符串。

  • 加密代码

...
public String MD5(String cipher) throws Exception{
MessageDigest m=MessageDigest.getInstance("MD5");
m.update(cipher.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);//将加密结果转化为16进制字符串
}
System.out.println("MD5加密后的结果:"+result);//输出加密后的结果
return result;//返回加密后的结果。
...
  • 服务器端中改动的代码:
   ...
String r=in.readUTF();//读取信息到r中(r是密文)
String plain=sDec.Plain(r);//将r解密得到明文
String message=digestPass.MD5(plain);//将解密后得到的明文用MD5算法加密,放入message中
String result=caculate.caculate(plain);//将解密后得到的算式进行运算
String q=in.readUTF();//得到用户端传送过来用MD5加密的明文q。
if(message.equals(q)){ //比较message和q,如果相等则校验成功,将计算结果返回。
System.out.println("校验成功!");
out.writeUTF(result);
...
  • 客户端中改动的代码:
   ...
String cipher=sEnc.Cipher(myBC.Behind);//将后缀表达式使用DES算法加密,得到密文cipher
out.writeUTF(cipher);把密文cipher写入流中以让服务器端读取。
out.writeUTF(digestPass.MD5(myBC.Behind));//将后缀表达式(明文)使用MD5算法加密,然后写入流中以让服务器端读取。
  • 客户端截图

  • 服务器端截图

四、码云链接

https://gitee.com/shengmaosong/java-besti-20175316/tree/master/shiyan5

五、实验过程中所遇到的问题

  • 问题一:在调试过程中,服务器端会出现

    Exception in thread "main" java.lang.NullPointerExcption

    从而导致监听不成功

    解决办法:原因是我没有将之前的服务器端口关闭,而是开了多个服务器端口,却使用了同样的端口,所以导致了这个情况。把之前的端口先关掉,问题就解决了。

六、实验感悟

  • 本次实验让我对网络编程与安全有了初步的了解,同时对于Java的密码学应用相比之前有了更深刻的认识。这次实验让我在Java、计算机网络、密码学三个方面有所学习有所进步,可以说是一举三得。因此我觉得这是一次很有意义的实验。

20175316 盛茂淞 2018-2019-2 《Java程序设计》实验五 《网络安全与编程》 实验报告的更多相关文章

  1. 20175316盛茂淞-Java第1周学习总结

    20175316盛茂淞 2018-2019-2 <Java程序设计>第1周学习总结 教材学习内容总结 Java入门 1.Java简介(地位,特点) 2.安装JDK,设置系统环境 3.编译J ...

  2. 20175316盛茂淞 2018-2019-2 《Java程序设计》第9周学习总结

    20175316盛茂淞 2018-2019-2 <Java程序设计>第9周学习总结 教材学习内容总结 下载安装MySQL数据库管理系统. 学习<Java程序设计>第十一章MyS ...

  3. 20175316盛茂淞 2018-2019-2 《Java程序设计》第8周学习总结

    20175316盛茂淞 2018-2019-2 <Java程序设计>第8周学习总结 教材学习内容总结 第十五章 泛型 -- 主要目的是可以建立具有类型安全的集合框架,如链表.散列映射等数据 ...

  4. 20175316 盛茂淞 2018-2019-2 《Java程序设计》实验二 面向对象程序设计 实验报告

    20175316 盛茂淞 2018-2019-2 <Java程序设计>实验二 面向对象程序设计 实验报告 (一)单元测试 在 IDEA中我们把产品代码放在src目录中,把测试代码放在tes ...

  5. 20175316盛茂淞 2018-2019-2 《Java程序设计》第7周学习总结

    20175316盛茂淞 2018-2019-2 <Java程序设计>第7周学习总结 教材学习内容总结 第八章 常用实用类 一.String类 String类在java.lang包中,jav ...

  6. 20175316盛茂淞 2018-2019-2 《Java程序设计》第6周学习总结

    20175316盛茂淞 2018-2019-2 <Java程序设计>第6周学习总结 教材学习内容总结 第7章 内部类与异常类 1.使用 try.catch Java中所有信息都会被打包为对 ...

  7. 20175316 盛茂淞 2018-2019-2 《Java程序设计》实验一 Java开发环境的熟悉 实验报告

    20175316 盛茂淞 2018-2019-2 <Java程序设计>实验一 Java开发环境的熟悉 实验报告 一.实验要求 1.使用JDK编译.运行简单的Java程序: 2.使用IDEA ...

  8. 20175316盛茂淞 2018-2019-2 《Java程序设计》第5周学习总结

    20175316盛茂淞 2018-2019-2 <Java程序设计>第5周学习总结 教材学习内容总结 第六章 接口与实现. 何谓接口 接口:书上没有明确地给出接口的定义,我理解的接口就是一 ...

  9. 20175316盛茂淞 2018-2019-2《Java程序设计》第4周学习总结

    20175316盛茂淞 2018-2019-2<Java程序设计>第4周学习总结 教材学习内容总结 第五章 子类与继承 一.继承 1.继承定义:避免多个类间重复定义共同行为 2.子类与父类 ...

随机推荐

  1. java利用webuploader实现超大文件分片上传、断点续传

    我们平时经常做的是上传文件,上传文件夹与上传文件类似,但也有一些不同之处,这次做了上传文件夹就记录下以备后用. 首先我们需要了解的是上传文件三要素: 1.表单提交方式:post (get方式提交有大小 ...

  2. P1608 路径统计

    题目描述 “RP餐厅”的员工素质就是不一般,在齐刷刷的算出同一个电话号码之后,就准备让HZH,TZY去送快餐了,他们将自己居住的城市画了一张地图,已知在他们的地图上,有N个地方,而且他们目前处在标注为 ...

  3. NetworkX系列教程(10)-算法之四:拓扑排序与最大流问题

    小书匠Graph图论 重头戏部分来了,写到这里我感觉得仔细认真点了,可能在NetworkX中,实现某些算法就一句话的事,但是这个算法是做什么的,用在什么地方,原理是怎么样的,不清除,所以,我决定先把图 ...

  4. Kmeans聚类(lena图)

    lena512.raw 下载地址:https://files.cnblogs.com/files/jzcbest1016/lena512_20171219131444306.rar .raw文件可以用 ...

  5. 配置centos7阿里镜像源和epel源

    [root@runstone yum.repos.d]# pwd /etc/yum.repos.d [root@runstone yum.repos.d]# cat aliBase.repo #镜像源 ...

  6. openfoam变热物性参数的设置【转载】

    转载自:http://blog.sina.com.cn/s/blog_9de422500102va73.html 物性参数在constant/thermophysicalProperties文件中设置 ...

  7. GDB使用——pwn相关

    目录 寄存器 内存 peda插件命令 x命令详解 后续补充 内容来源 寄存器 1.查看寄存器 2.查看所有寄存器 3.查看某个寄存器 4.修改寄存器的值 内存 1.修改内存值 2.搜索内存 peda插 ...

  8. 小福bbs—项目系统设计与数据库设计

    这个作业属于哪个课程 班级链接 这个作业要求在哪里 作业要求的链接 团队名称 小福bbs 这个作业的目标 实现对校园论坛软件的制作,使其能够发布帖子,查看信息等 作业的正文 小福bbs--项目需求分析 ...

  9. postgresql 的 .pgpass密码文件的使用

    pgpass 是 连接 postgresql 时使用的密码文件,通常位置为 ~/.pgpass.在使用某些组件时还真的必须使用.具体的格式为: hostname:port:database:usern ...

  10. Flutter移动电商实战 --(43)详细页_补充首页跳转到详细页

    首页轮播点击到详细页 修改我们轮播这里的代码:SwiperDiy这个类这里的代码 return InkWell( onTap: (){ Application.router.navigateTo(co ...