课程:Java程序设计 班级:1652班 姓名:王高源 学号:20165225 指导教师:娄嘉鹏 实验日期:2018年5月14日 实验时间:3:35 - 5:15 实验序号:实验5 实验名称:网络编程与安全 实验内容: 一、掌握Java Socket的相关内容; 二、学会创建客户端与服务器端之间的联系; 三、学习并应用密码学的相关内容 严禁抄袭,有该行为者实验成绩归零,并附加其余惩罚措施。
实验要求:html
两人一组结对编程:java
参考http://www.cnblogs.com/rocedu/p/6766748.html#SECDSA
结对实现中缀表达式转后缀表达式的功能 MyBC.java
结对实现从上面功能中获取的表达式中实现后缀表达式求值的功能,调用MyDC.java算法
实验代码:express
Client编程
import java.net.*; import java.io.*; public class Client { public static void main(String srgs[]) throws Exception { try { // 一、建立客户端Socket,指定服务器地址和端口 Socket socket=new Socket("127.0.0.1",10000); System.out.println("客户端成功启动,等待服务器应答"); // 二、获取输出流,向服务器端发送信息 // 向本机的10001端口发出客户请求 System.out.println("请输入中缀表达式:"); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 由系统标准输入设备构造BufferedReader对象 PrintWriter write = new PrintWriter(socket.getOutputStream()); // 由Socket对象获得输出流,并构造PrintWriter对象 //三、获取输入流,并读取服务器端的响应信息 BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); // 由Socket对象获得输入流,并构造相应的BufferedReader对象 String readline, infix, expression; readline = br.readLine(); // 从系统标准输入读入一字符串 MyBC theTrans = new MyBC(readline); infix = theTrans.doTrans(); StringBuilder newInfix = new StringBuilder(infix.replace(" ","")); for (int i = 1; i < infix.length()+(i+1)/2 ; i=i+2) { newInfix.insert(i," "); } System.out.println("后缀表达式:" + newInfix); expression=newInfix.toString(); while (!readline.equals("end")) { // 若从标准输入读入的字符串为 "end"则中止循环 write.println(expression); // 将从系统标准输入读入的字符串输出到Server write.flush(); // 刷新输出流,使Server立刻收到该字符串 System.out.println("收到服务器的消息:" + in.readLine()); // 从Server读入一字符串,并打印到标准输出上 readline = br.readLine(); // 从系统标准输入读入一字符串 } // 继续循环 //四、关闭资源 write.close(); // 关闭Socket输出流 in.close(); // 关闭Socket输入流 socket.close(); // 关闭Socket } catch (Exception e) { System.out.println(e);//输出异常 } finally { } } }
Server数组
import java.net.*; import java.io.*; public class Server{ public static void main(String srgs[]) throws Exception { ServerSocket sc = null; Socket socket=null; try { MyDC evaluator = new MyDC(); sc= new ServerSocket(10000);//建立服务器套接字 System.out.println("端口号:" + sc.getLocalPort()); System.out.println("服务器成功启动,等待客户端呼叫"); socket = sc.accept(); //等待客户端链接 System.out.println("已经创建链接");//得到网络输入流对象的引用 BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));//得到网络输出流对象的引用 PrintWriter out=new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true); String aline2=in.readLine(); System.out.println("客户端发来的信息为:"+aline2); int ans = evaluator.evaluate(aline2); out.println(ans); System.out.println("result = "+ans); } catch (Exception e) { System.out.println(e); } } //十六进制和十进制转换 public static byte[] parseHexStr2Byte(String hexStr) { if (hexStr.length() < 1) return null; byte[] result = new byte[hexStr.length()/2]; for (int i = 0;i< hexStr.length()/2; i++) { int high = Integer.parseInt(hexStr.substring(i*2, i*2+1 ), 16); int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16); result[i] = (byte) (high * 16 + low); } return result; } }
MyDc安全
import java.util.StringTokenizer; 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(); //若是是运算符,调用isOperator if (isOperator(token)) { //从栈中弹出操做数2 op2 = stack.pop(); //从栈中弹出操做数1 op1 = stack.pop(); //根据运算符和两个操做数调用evalSingleOp计算result; result=evalSingleOp(token.charAt(0), op1, op2); //计算result入栈; stack.push(result); } else//若是是操做数 //操做数入栈; stack.push(Integer.parseInt(token)); } return result; } private boolean isOperator(String token) { 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; } }
MyBc服务器
public class MyBC { private Stack theStack; private String input; private String output = ""; public MyBC(String in) { input = in; int stackSize = input.length(); theStack = new Stack(stackSize); } public String doTrans() { for (int j = 0; j < input.length(); j++) { char ch = input.charAt(j); switch (ch) { case '+': case '-': gotOper(ch, 1); break; case '*': case '/': gotOper(ch, 2); break; case '(': theStack.push(ch); break; case ')': gotParen(ch); break; default: output = output + ch; break; } } while (!theStack.isEmpty()) { output = output + theStack.pop(); } return output; } public void gotOper(char opThis, int prec1) { while (!theStack.isEmpty()) { char opTop = theStack.pop(); if (opTop == '(') { theStack.push(opTop); break; } else { int prec2; if (opTop == '+' || opTop == '-') prec2 = 1; else prec2 = 2; if (prec2 < prec1) { theStack.push(opTop); break; } else output = output + opTop; } } theStack.push(opThis); } public void gotParen(char ch){ while (!theStack.isEmpty()) { char chx = theStack.pop(); if (chx == '(') break; else output = output + chx; } } class Stack { private int maxSize; private char[] stackArray; private int top; public Stack(int max) { maxSize = max; stackArray = new char[maxSize]; top = -1; } public void push(char j) { stackArray[++top] = j; } public char pop() { return stackArray[top--]; } public char peek() { return stackArray[top]; } public boolean isEmpty() { return (top == -1); } } }
实验截图:网络
结对编程:1人负责客户端,一人负责服务器socket
注意责任归宿,要会经过测试证实本身没有问题
基于Java Socket实现客户端/服务器功能,传输方式用TCP
客户端让用户输入中缀表达式,而后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式经过网络发送给服务器
服务器接收到后缀表达式,调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
客户端显示服务器发送过来的结果
实验代码:
Server
import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class Server1 { public static void main(String args[]) { ServerSocket serverForClient = null; Socket socketOnServer = null; DataOutputStream out = null; DataInputStream in = null; try { serverForClient = new ServerSocket(3001); } catch (IOException e1) { System.out.println(e1); } try { System.out.println("等待客户呼叫"); socketOnServer = serverForClient.accept(); //堵塞状态,除非有客户呼叫 System.out.println("客户已链接"); out = new DataOutputStream(socketOnServer.getOutputStream()); in = new DataInputStream(socketOnServer.getInputStream()); String leng = in.readUTF(); // in读取信息,堵塞状态 byte ctext[] = new byte[Integer.parseInt(leng)]; for (int i = 0;i<Integer.parseInt(leng);i++) { String temp = in.readUTF(); ctext[i] = Byte.parseByte(temp); } // 获取密钥 FileInputStream f2 = new FileInputStream("keykb1.txt"); 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); System.out.println("后缀表达式已被解密:"); for (int i = 0; i < ptext.length; i++) { System.out.print(ptext[i] + ","); } System.out.println(""); // 显示明文 String p = new String(ptext, "UTF8"); System.out.println("服务器收到客户的请求:计算后缀表达式" + p); MyDC evaluator = new MyDC(); out.writeUTF(evaluator.evaluate(p)+""); } catch (Exception e) { System.out.println("客户已断开" + e); } } }
Client
实验截图:
加密结对编程:1人负责客户端,一人负责服务器
注意责任归宿,要会经过测试证实本身没有问题
基于Java Socket实现客户端/服务器功能,传输方式用TCP
客户端让用户输入中缀表达式,而后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密后经过网络把密文发送给服务器
服务器接收到后缀表达式表达式后,进行解密(和客户端协商密钥,能够用数组保存),而后调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
客户端显示服务器发送过来的结果
实验代码:
Server
import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.security.Key; import java.util.Optional; public class Server2 { public static void main(String args[]) { ServerSocket serverForClient = null; Socket socketOnServer = null; DataOutputStream out = null; DataInputStream in = null; try { serverForClient = new ServerSocket(2010); } catch (IOException e1) { System.out.println(e1); } try { System.out.println("等待客户呼叫"); socketOnServer = serverForClient.accept(); //堵塞状态,除非有客户呼叫 System.out.println("客户已链接"); out = new DataOutputStream(socketOnServer.getOutputStream()); in = new DataInputStream(socketOnServer.getInputStream()); Key_DH.fun("Spub.txt","Spri.txt"); int len = Integer.parseInt(in.readUTF()); byte np[] = new byte[len]; for (int i = 0;i<len;i++) { String temp = in.readUTF(); np[i] = Byte.parseByte(temp); } ObjectInputStream ois = new ObjectInputStream (new ByteArrayInputStream (np)); Key k2 = (Key)ois.readObject();; FileOutputStream f2 = new FileOutputStream("Cpub.txt"); ObjectOutputStream b2 = new ObjectOutputStream(f2); b2.writeObject(k2); FileInputStream fp = new FileInputStream("Spub.txt"); ObjectInputStream bp = new ObjectInputStream(fp); Key kp = (Key) bp.readObject(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(kp); byte[] kb = baos.toByteArray(); out.writeUTF(kb.length + ""); for (int i = 0; i < kb.length; i++) { out.writeUTF(kb[i] + ""); } KeyAgree.fun("Cpub.txt","Spri.txt"); String leng = in.readUTF(); // in读取信息,堵塞状态 byte ctext[] = new byte[Integer.parseInt(leng)]; for (int i = 0;i<Integer.parseInt(leng);i++) { String temp = in.readUTF(); ctext[i] = Byte.parseByte(temp); } // 获取密钥 FileInputStream f = new FileInputStream("sb.txt"); byte[] keysb = new byte[24]; f.read(keysb); System.out.println("公共密钥:"); for (int i = 0;i<24;i++) { System.out.print(keysb[i]+","); } System.out.println(""); SecretKeySpec k = new SecretKeySpec(keysb, "DESede"); // 解密 Cipher cp = Cipher.getInstance("DESede"); cp.init(Cipher.DECRYPT_MODE, k); byte[] ptext = cp.doFinal(ctext); System.out.println("后缀表达式已被解密:"); for (int i = 0; i < ptext.length; i++) { System.out.print(ptext[i] + ","); } System.out.println(""); // 显示明文 String p = new String(ptext, "UTF8"); System.out.println("服务器收到客户的请求:计算后缀表达式" + p); MyDC evaluator = new MyDC(); out.writeUTF(evaluator.evaluate(p)+""); } catch (Exception e) { System.out.println("客户已断开" + e); } } }
实验编程:
密钥分发结对编程:1人负责客户端,一人负责服务器
注意责任归宿,要会经过测试证实本身没有问题
基于Java Socket实现客户端/服务器功能,传输方式用TCP
客户端让用户输入中缀表达式,而后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密经过网络把密文发送给服务器
客户端和服务器用DH算法进行3DES或AES算法的密钥交换
服务器接收到后缀表达式表达式后,进行解密,而后调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
客户端显示服务器发送过来的结果
实验代码:
server
import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.security.Key; public class Server3 { public static void main(String args[]) { ServerSocket serverForClient = null; Socket socketOnServer = null; DataOutputStream out = null; DataInputStream in = null; try { serverForClient = new ServerSocket(3001); } catch (IOException e1) { System.out.println(e1); } try { System.out.println("等待客户呼叫"); socketOnServer = serverForClient.accept(); //堵塞状态,除非有客户呼叫 System.out.println("客户已链接"); out = new DataOutputStream(socketOnServer.getOutputStream()); in = new DataInputStream(socketOnServer.getInputStream()); Key_DH.fun("Spub.txt","Spri.txt"); int len = Integer.parseInt(in.readUTF()); byte np[] = new byte[len]; for (int i = 0;i<len;i++) { String temp = in.readUTF(); np[i] = Byte.parseByte(temp); } ObjectInputStream ois = new ObjectInputStream (new ByteArrayInputStream(np)); Key k2 = (Key)ois.readObject();; FileOutputStream f2 = new FileOutputStream("Cpub.txt"); ObjectOutputStream b2 = new ObjectOutputStream(f2); b2.writeObject(k2); FileInputStream fp = new FileInputStream("Spub.txt"); ObjectInputStream bp = new ObjectInputStream(fp); Key kp = (Key) bp.readObject(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(kp); byte[] kb = baos.toByteArray(); out.writeUTF(kb.length + ""); for (int i = 0; i < kb.length; i++) { out.writeUTF(kb[i] + ""); } KeyAgree.fun("Cpub.txt","Spri.txt"); String leng = in.readUTF(); // in读取信息,堵塞状态 byte ctext[] = new byte[Integer.parseInt(leng)]; for (int i = 0;i<Integer.parseInt(leng);i++) { String temp = in.readUTF(); ctext[i] = Byte.parseByte(temp); } String check = in.readUTF(); // 获取密钥 FileInputStream f = new FileInputStream("sb.txt"); byte[] keysb = new byte[24]; f.read(keysb); System.out.println("公共密钥:"); for (int i = 0;i<24;i++) { System.out.print(keysb[i]+","); } System.out.println(""); SecretKeySpec k = new SecretKeySpec(keysb, "DESede"); // 解密 Cipher cp = Cipher.getInstance("DESede"); cp.init(Cipher.DECRYPT_MODE, k); byte[] ptext = cp.doFinal(ctext); System.out.println("后缀表达式已被解密:"); for (int i = 0; i < ptext.length; i++) { System.out.print(ptext[i] + ","); } System.out.println(""); // 显示明文 String p = new String(ptext, "UTF8"); String pMd5 = DigestPass.fun(p); System.out.println("解密后明文的MD5值:"+pMd5); if (pMd5.equals(check)){ System.out.println("和客户端的MD5值一致"); System.out.println("服务器收到客户的请求:计算后缀表达式" + p); MyDC evaluator = new MyDC(); out.writeUTF(evaluator.evaluate(p)+""); } else { System.out.println("警告:和客户端的MD5值不一致!"); } } catch (Exception e) { System.out.println("客户已断开" + e); } } }
实验截图:
完整性校验结对编程:1人负责客户端,一人负责服务器
注意责任归宿,要会经过测试证实本身没有问题
基于Java Socket实现客户端/服务器功能,传输方式用TCP
客户端让用户输入中缀表达式,而后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密经过网络把密文和明文的MD5値发送给服务器
客户端和服务器用DH算法进行3DES或AES算法的密钥交换
服务器接收到后缀表达式表达式后,进行解密,解密后计算明文的MD5值,和客户端传来的MD5进行比较,一致则调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
客户端显示服务器发送过来的结果
实验代码:
Client
import java.net.*; import java.io.*; public class Client { public static void main(String srgs[]) throws Exception { try { // 一、建立客户端Socket,指定服务器地址和端口 Socket socket=new Socket("127.0.0.1",10000); System.out.println("客户端成功启动,等待服务器应答"); // 二、获取输出流,向服务器端发送信息 // 向本机的10001端口发出客户请求 System.out.println("请输入中缀表达式:"); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 由系统标准输入设备构造BufferedReader对象 PrintWriter write = new PrintWriter(socket.getOutputStream()); // 由Socket对象获得输出流,并构造PrintWriter对象 //三、获取输入流,并读取服务器端的响应信息 BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); // 由Socket对象获得输入流,并构造相应的BufferedReader对象 String readline, infix, expression; readline = br.readLine(); // 从系统标准输入读入一字符串 MyBC theTrans = new MyBC(readline); infix = theTrans.doTrans(); StringBuilder newInfix = new StringBuilder(infix.replace(" ","")); for (int i = 1; i < infix.length()+(i+1)/2 ; i=i+2) { newInfix.insert(i," "); } System.out.println("后缀表达式:" + newInfix); expression=newInfix.toString(); while (!readline.equals("end")) { // 若从标准输入读入的字符串为 "end"则中止循环 write.println(expression); // 将从系统标准输入读入的字符串输出到Server write.flush(); // 刷新输出流,使Server立刻收到该字符串 System.out.println("收到服务器的消息:" + in.readLine()); // 从Server读入一字符串,并打印到标准输出上 readline = br.readLine(); // 从系统标准输入读入一字符串 } // 继续循环 //四、关闭资源 write.close(); // 关闭Socket输出流 in.close(); // 关闭Socket输入流 socket.close(); // 关闭Socket } catch (Exception e) { System.out.println(e);//输出异常 } finally { } } }import java.net.*; import java.io.*; public class Client { public static void main(String srgs[]) throws Exception { try { // 一、建立客户端Socket,指定服务器地址和端口 Socket socket=new Socket("127.0.0.1",10000); System.out.println("客户端成功启动,等待服务器应答"); // 二、获取输出流,向服务器端发送信息 // 向本机的10001端口发出客户请求 System.out.println("请输入中缀表达式:"); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 由系统标准输入设备构造BufferedReader对象 PrintWriter write = new PrintWriter(socket.getOutputStream()); // 由Socket对象获得输出流,并构造PrintWriter对象 //三、获取输入流,并读取服务器端的响应信息 BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); // 由Socket对象获得输入流,并构造相应的BufferedReader对象 String readline, infix, expression; readline = br.readLine(); // 从系统标准输入读入一字符串 MyBC theTrans = new MyBC(readline); infix = theTrans.doTrans(); StringBuilder newInfix = new StringBuilder(infix.replace(" ","")); for (int i = 1; i < infix.length()+(i+1)/2 ; i=i+2) { newInfix.insert(i," "); } System.out.println("后缀表达式:" + newInfix); expression=newInfix.toString(); while (!readline.equals("end")) { // 若从标准输入读入的字符串为 "end"则中止循环 write.println(expression); // 将从系统标准输入读入的字符串输出到Server write.flush(); // 刷新输出流,使Server立刻收到该字符串 System.out.println("收到服务器的消息:" + in.readLine()); // 从Server读入一字符串,并打印到标准输出上 readline = br.readLine(); // 从系统标准输入读入一字符串 } // 继续循环 //四、关闭资源 write.close(); // 关闭Socket输出流 in.close(); // 关闭Socket输入流 socket.close(); // 关闭Socket } catch (Exception e) { System.out.println(e);//输出异常 } finally { } } }
实验截图:
步骤 | 耗时 | 百分比 |
---|---|---|
功能实现 | 55min | 12.5% |
测试 | 25min | 15.6% |
分析总结 | 20min | 12.5% |