20172303 2017-2018-2 《程序设计与数据结构》实验五报告

20172303 2017-2018-2 《程序设计与数据结构》实验五报告

  • 课程:《程序设计与数据结构》
  • 班级: 1723
  • 姓名: 范雯琪
  • 学号:20172303
  • 实验教师:王志强
  • 助教:张旭升/刘伟康
  • 实验日期:2018年6月13日
  • 必修/选修: 必修

实验内容

  • 任务一:实现中缀转后缀并计算结果的功能
    • 参考数据结构应用
    • 结对实现中缀表达式转后缀表达式的功能 MyBC.java
    • 结对实现从上面功能中获取的表达式中实现后缀表达式求值的功能,调用MyDC.java
  • 任务二:基于Java Socket实现客户端/服务器功能
    • 一人负责客户端,一人负责服务器
    • 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式通过网络发送给服务器
    • 服务器接收到后缀表达式,调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
    • 客户端显示服务器发送过来的结果
  • 任务三:基于任务二,使用3DES或AES算法将后缀表达式进行加密
    • 一人负责客户端,一人负责服务器
    • 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密后通过网络把密文发送给服务器
    • 服务器接收到后缀表达式表达式后,进行解密(和客户端协商密钥,可以用数组保存),然后调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
    • 客户端显示服务器发送过来的结果
  • 任务四:基于任务三,使用DH进行密钥交换
    • 一人负责客户端,一人负责服务器
    • 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密通过网络把密文发送给服务器
    • 客户端和服务器用DH算法进行3DES或AES算法的密钥交换
    • 服务器接收到后缀表达式表达式后,进行解密,然后调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
    • 客户端显示服务器发送过来的结果
  • 任务五:基于任务四,使用MD5将明文加密
    • 一人负责客户端,一人负责服务器
    • 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密通过网络把密文和明文的MD5値发送给服务器
    • 客户端和服务器用DH算法进行3DES或AES算法的密钥交换
    • 服务器接收到后缀表达式表达式后,进行解密,解密后计算明文的MD5值,和客户端传来的MD5进行比较,一致则调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
    • 客户端显示服务器发送过来的结果

实验过程及结果

任务一

过程

  • 因为在之前的结对编程中已经实现了这两个功能,并且老师说可以直接使用,我就直接使用了之前的InfixToSuffix类和Calculator类进行中缀转后缀和计算,在ArithmeticTest类中添加代码后实现。

运行结果

任务二

原理

TCP协议

  • TCP是Tranfer Control Protocol的简称,是一种面向连接的保证可靠传输的协议.通过TCP协议传输,得到的是一个顺序的无差错的数据流。
  • 发送方和接收方的成对的两个socket之间必须建立连接,以便在TCP协议的基础上进行通信,当一个socket(通常都是server socket)等待建立连接时,另一个socket可以要求进行连接,一旦这两个socket连接起来,它们就可以进行双向数据传输,双方都可以进行发送或接收操作。
  • TCP在网络通信上有极强的生命力,例如远程连接(Telnet)和文件传输(FTP)都需要不定长度的数据被可靠地传输。但是可靠的传输是要付出代价的,对数据内容正确性的检验必然占用计算机的处理时间和网络的带宽

Java.net.Socket

  • 此类实现客户端套接字(也可以就叫“套接字”)。套接字是两台机器间通信的端点。
    套接字的实际工作由 SocketImpl类的实例执行。应用程序通过更改创建套接字实现的套接字工厂可以配置它自身,以创建适合本地防火墙的套接字。
  • java在包java.net中提供了两个类SocketServerSocket,分别用来表示双向连接的客户端和服务端。这是两个封装得非常好的类,使用很方便。
  • 构造方法

    其中address、host和port分别是双向连接中另一方的IP地址、主机名和端口号,stream指明socket是流socket还是数据报socket,localPort表示本地主机的端口号,localAddr和bindAddr是本地机器的地址(ServerSocket的主机地址),impl是socket的父类,既可以用来创建serverSocket又可 以用来创建Socket。count则表示服务端所能支持的最大连接数。例如:
  Socket client = new Socket("127.0.01.", 80);
  ServerSocket server = new ServerSocket(80);
  • 注意,在选择端口时,必须小心。每一个端口提供一种特定的服务,只有给出正确的端口,才能获得相应的服务。0~1023的端口号为系统所保留,例如http服务的端口号为80,telnet服务的端口号为21,ftp服务的端口号为23, 所以我们在选择端口号时,最好选择一个大于1023的数以防止发生冲突。

过程

  • 使用ipconfig在cmd中查看自己的IP地址,要注意的是,在创建Socket的时候,如果是和结对伙伴的话,host要填结对伙伴的IP,而如果是自己既做客户端又做服务器时,host可以填127.0.0.1或localhost。
  • 客户端
    • 创建Socket
    //1.建立客户端Socket连接,指定服务器位置和端口
        Socket socket = new Socket("172.16.43.217",8800);
    
    • 打开连接到Socket的输入流
    //2.得到socket读写流
    OutputStream outputStream = socket.getOutputStream();
    PrintWriter(outputStream);
    OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
    //输入流
    InputStream inputStream = socket.getInputStream();
    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));
    
    • 按照一定的协议对Socket进行读/写操作
    Scanner scanner = new Scanner(System.in);
    System.out.println("请输入计算式:(以空格隔开每个运算符和运算数)");
    String expr = scanner.nextLine();
    InfixToSuffix infixToSuffix = new InfixToSuffix();
    infixToSuffix.conversion(expr);
    System.out.println("我传送给服务器的信息为:"+infixToSuffix.getMessage());
    String info = new String(infixToSuffix.getMessage().getBytes("utf-8"));
    outputStreamWriter.write(info);
    outputStreamWriter.flush();
    socket.shutdownOutput();
    //接收服务器的响应
    String reply = null;
    while (!((reply = bufferedReader.readLine()) == null)){
        System.out.println("接收服务器的信息为:" + reply);
    }
    
    • 关闭Socket
    bufferedReader.close();
    inputStream.close();
    outputStreamWriter.close();
    outputStream.close();
    socket.close();
    
  • 服务器
  • 服务器部分是我的结对伙伴完成的,这里放他的码云链接,其大致过程仍然是:
    • 创建Socket
    • 打开连接到Socket的输入/出流
    • 按照一定的协议对Socket进行读/写操作
    • 关闭Socket

运行结果


任务三

原理

DES加密算法

  • DES加密是一种对称加密算法,它是分组密钥的代表算法,算法和密钥都需要良好的加密。
  • 实现DES对称密钥的步骤有三步:
    • 生成对称密钥;
    • 使用对称密钥进行加密和解密;
    • 从文件中获取加密时使用的密钥,使用密钥进行解密。
  • 关键代码
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);
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);

过程

  • 刚开始我们在任务二的基础上进行代码增加,但是在运行时服务器端显示的是乱码,后来发现是因为传输的格式有问题,娄老师的博客里给的解密方式解密的必须是byte数组,之后我们就想办法把传过来的信息的格式改成byte数组,但是尝试了很多次都失败了。
  • 而在在上网查的时候发现一篇博客中java的OutputStream.writeUTF()函数介绍了另一种方法:DataOutputStream/DataInputStream,其中有一个方法叫wrtieUTF,它将 UTF-8 字符串写入字节流。先写入以字节表示的 UTF-8 字符串长度(作为 16 位整数),然后写入表示字符串字符的字节。使用这个方法,在传输之后转化成byte数组就很方便了。
  • 客户端
  • 服务器

运行结果


任务四

原理

DH算法

  • 在DH算法中,主要数据通过对称密钥加密,而使用非对称加密来分发对称密钥,这样就将两者的优势结合了起来。
  • DH算法是建立在DH公钥和私钥的基础上的,A需要和B共享密钥时,A和B各自生成DH公钥和私钥,公钥对外公布而私钥各自秘密保存。

过程

  • 1.修改原先的key_DH类和keyAgree类中的main方法,使其能够被引用。

  • 2.创建DH公钥和私钥,将生成的公钥文件传给对方
    客户端

    服务器

运行结果


任务五

原理

  • 使用Java计算指定字符串的消息摘要。java.security包中的MessageDigest类提供了计算消息摘要的方法。
  • 运行代码
    String x=args[0];
    MessageDigest m=MessageDigest.getInstance("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:在第一次运行Socket时抛出IOException错误。
  • 问题1解决方法:通过在网上查找发现这个错误好像是避免不了的,必须进行捕获或者抛出。

在创建socket时如果发生错误,将产生IOException,在程序中必须对之作出处理。所以在创建Socket或ServerSocket是必须捕获或抛出例外。

  • 问题2:在传输的过程中产生错误javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
  • 问题2解决方法:通过翻译,产生的原因应该是因为服务器和客户端产生的密钥不同,在把我的密钥文件复制给他之后就解决了问题。
  • 问题3:在任务三传输的过程中,传输过去的一直显示的是乱码
  • 问题3解决方法:在刚刚的任务三的实验过程中有写到,我们找到了另外一种方法来解决这个问题。

其他(感悟、思考等)

  • 本学期的最后一次实验了,感觉java socket真的非常有意思,最后悔的是当时实验三的最后一个节点做的不是很好,所以这回又去复习了半天密码学的相关内容。
    回顾一个学期的内容发现自己真的学到了很多,很开心。
  • 下学期继续加油。

参考资料

posted @ 2018-06-19 21:08  框框框  阅读(347)  评论(0编辑  收藏  举报