上传测试代码运行结果截图和码云连接html
将运算符写在两个操做数中间的表达式,称为“中缀表达式”,如1+2(3-4)+5。在中缀表达式中,运算符具备不一样的优先级,圆括号用于改变运算符的运算次序,因此求值过程不能直接按照从左到右的顺序进行。
将运算符写在两个操做数以后的表达式称为“后缀表达式”,如上面的中缀表达式可转换为后缀表达式1 2 3 4 - + 5 +。后缀表达式中没有括号,并且运算符没有优先级。后缀表达式的求值过程可以严格地从左到右按顺序进行,符合运算器的求值规律。
表达式求值算法分两步进行:①中缀转后缀;②求后缀表达式的值。
①中缀转后缀的算法可描述为:java
设置一个运算符栈,设置一个后缀表达式字符串;
从左到右依次对中缀表达式中的每一个字符ch分别进行如下处理,直至表达式结束:
若ch是左括号‘(’,将其入栈;
若ch是数字,将其后连续若干数字添加到后缀表达式字符串以后,并添加空格做为分隔符;
若ch是运算符,先将栈顶若干优先级高于ch的运算符出栈,添加到后缀表达式字符串以后,再将ch入栈。当‘(’运算符在栈中时,它的优先级最低。
若ch是‘)’,则若干运算符所有出栈,直到出栈的是左括号,一对括号匹配。
若表达式结束,将栈中运算符所有出栈,添加到后缀表达式字符串以后。
中缀转后缀的代码为:算法
public static String toPostfix(String expr){ MyStack<String> stack = new MyStack<>(expr.length()); String postfix = ""; int i = 0; while(i<expr.length()){ char ch = expr.charAt(i); switch (ch){ case '+': case '-':while(!stack.isEmpty() && !stack.get().equals("(")) postfix += stack.pop(); //postfix += " "; stack.push(ch + ""); i++; break; case '*': case '/':while (!stack.isEmpty() && (stack.get().equals("*")||stack.get().equals("/"))) postfix += stack.pop(); //postfix += " "; stack.push(ch + ""); i++; break; case '(':stack.push(ch + ""); i++; break; case ')':String out = stack.pop(); while(out!=null && !out.equals("(")){ postfix += out; out = stack.pop(); //postfix += " "; } i++; break; default:while(i < expr.length() && ch>='0' && ch<='9'){ postfix += ch; i++; if(i<expr.length()) ch = expr.charAt(i); } postfix += " "; } } while (!stack.isEmpty()) postfix += stack.pop(); return postfix; }
②后缀表达式求值的算法可描述为express
设置一个操做数栈,从左向右依次对后缀表达式字符串中的每一个字符ch进行处理;
若ch是数字,先将其后连续若干数字转化为整数,再将该整数入栈;
若ch是运算符,出栈两个值进行运算,运算结果再入栈;
重复以上步骤,直至后缀表达式结束,栈中最后一个数字就是所求表达式的值。
后缀表达式求值的代码为:编程
public int value(String postfix){ Stack<Integer> stack = new Stack(); int i = 0, result = 0; while(i < postfix.length()){ char ch = postfix.charAt(i); if(ch>='0' && ch<='9'){ result = 0; while(ch!=' '){ result = result*10 + Integer.parseInt(ch+""); i++; ch = postfix.charAt(i); } i++; stack.push(new Integer(result)); } else{ int y = stack.pop().intValue(); int x = stack.pop().intValue(); switch (ch){ case ADD: result = x + y; break; case SUBTRACT: result = x - y; break; case MULTIPLY: result = x * y; break; case DIVIDE: result = x / y; } stack.push(new Integer(result)); i++; } } return stack.pop().intValue(); }
最后添加测试代码便可:数组
public class NewMyDCTester { public static void main(String [] args) { String expression; int result; try { Scanner in = new Scanner(System.in); NewMyDC evaluator = new NewMyDC(); System.out.println ("Enter a valid postfix expression: "); expression = in.nextLine(); String postfix = MyBC.toPostfix(expression); System.out.println ("The postfix expression is :" + postfix); result = evaluator.value (postfix); System.out.println ("That expression equals :" + result); } catch (Exception IOException) { System.out.println("Input exception reported"); } } }
运行结果以下:
安全
结对编程:1人负责客户端,一人负责服务器
0.注意责任归宿,要会经过测试证实本身没有问题
1.基于Java Socket实现客户端/服务器功能,传输方式用TCP
2.客户端让用户输入中缀表达式,而后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式经过网络发送给服务器
3.服务器接收到后缀表达式,调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
4.客户端显示服务器发送过来的结果
5.上传测试结果截图和码云连接服务器
java.net.Socket与java.net.ServerSocket网络
『java.net.Socket』:并发
套接字是一个网络链接的端点。在java中,使用java.net.Socket对象来表示一个套接字。
要建立一个套接字,可使用Socket的构造方法,如:public Socket(java.lang.String host, int port)。其中,host是远程机器名或IP地址,port是远程应用程序的端口号。
一旦成功建立了Socket类的一个实例,就可使用它发送或接收字节流。要发送字节流,必须先调用Socket类的getOutputStream方法来获取一个java.io.OutputStream对象。要向远程应用程序发送文本,一般要从返回的OutputStream对象构建一个java.io.PrintWriter对象。要接收来自链接的另外一端的字节流,能够调用Socket类的getInputStream方法,它返回一个java.io.InputStream。
如下代码建立了一个客户端:
// 一、建立客户端Socket,指定服务器地址和端口 Socket socket=new Socket("127.0.0.1",5200); //Socket socket = new Socket("192.168.1.115", 5209); System.out.println("客户端启动成功"); // 二、获取输出流,向服务器端发送信息 // 向本机的5200端口发出客户请求 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; readline = br.readLine(); // 从系统标准输入读入一字符串 while (!readline.equals("end")) { // 若从标准输入读入的字符串为 "end"则中止循环 write.println(readline); // 将从系统标准输入读入的字符串输出到Server write.flush(); // 刷新输出流,使Server立刻收到该字符串 System.out.println("Client:" + readline); // 在系统标准输出上打印读入的字符串 System.out.println("Server:" + in.readLine()); // 从Server读入一字符串,并打印到标准输出上 readline = br.readLine(); // 从系统标准输入读入一字符串 } // 继续循环 //四、关闭资源 write.close(); // 关闭Socket输出流 in.close(); // 关闭Socket输入流 socket.close(); // 关闭Socket
『java.net.ServerSocket』:
ServerSocket是服务器套接字的一个实现。ServerSocket和Socket不一样,服务器套接字的角色是,等待来自客户端的链接请求。一旦服务器套接字得到了一个链接请求,它就会建立一个Socket实例,以处理和客户端的通讯。
如下代码建立了一个服务器:
//搭建服务器端 public static void main(String[] args) throws IOException{ SocketService socketService = new SocketService(); //一、a)建立一个服务器端Socket,即SocketService socketService.oneServer(); } public void oneServer(){ try{ ServerSocket server=null; try{ server=new ServerSocket(5200); //b)指定绑定的端口,并监听此端口。 System.out.println("服务器启动成功"); //建立一个ServerSocket在端口5209监听客户请求 }catch(Exception e) { System.out.println("没有启动监听:"+e); //出错,打印出错信息 } Socket socket=null; try{ socket=server.accept(); //二、调用accept()方法开始监听,等待客户端的链接 //使用accept()阻塞等待客户请求,有客户 //请求到来则产生一个Socket对象,并继续执行 }catch(Exception e) { System.out.println("Error."+e); //出错,打印出错信息 } //三、获取输入流,并读取客户端信息 String line; BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream())); //由Socket对象获得输入流,并构造相应的BufferedReader对象 PrintWriter writer=new PrintWriter(socket.getOutputStream()); //由Socket对象获得输出流,并构造PrintWriter对象 BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); //由系统标准输入设备构造BufferedReader对象 System.out.println("Client:"+in.readLine()); //在标准输出上打印从客户端读入的字符串 line=br.readLine(); //从标准输入读入一字符串 //四、获取输出流,响应客户端的请求 while(!line.equals("end")){ //若是该字符串为 "bye",则中止循环 writer.println(line); //向客户端输出该字符串 writer.flush(); //刷新输出流,使Client立刻收到该字符串 System.out.println("Server:"+line); //在系统标准输出上打印读入的字符串 System.out.println("Client:"+in.readLine()); //从Client读入一字符串,并打印到标准输出上 line=br.readLine(); //从系统标准输入读入一字符串 } //继续循环 //五、关闭资源 writer.close(); //关闭Socket输出流 in.close(); //关闭Socket输入流 socket.close(); //关闭Socket server.close(); //关闭ServerSocket }catch(Exception e) {//出错,打印出错信息 System.out.println("Error."+e); } }
建立了客户端和服务器,调用任务一中的中缀表达式转后缀表达式与后缀表达式求值的方法便可。运行结果以下:
加密结对编程:1人负责客户端,一人负责服务器
0.注意责任归宿,要会经过测试证实本身没有问题
1.基于Java Socket实现客户端/服务器功能,传输方式用TCP
2.客户端让用户输入中缀表达式,而后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密后经过网络把密文发送给服务器
3.服务器接收到后缀表达式表达式后,进行解密(和客户端协商密钥,能够用数组保存),而后调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
4.客户端显示服务器发送过来的结果
5.上传测试结果截图和码云连接
实现DES加密主要有如下几个步骤:
对称密钥的生成和保存;
使用对称密钥进行加密和解密;
从文件中获取加密时使用的密钥,使用密钥进行解密;
客户端加密并发送至服务器部分的代码以下:
KeyGenerator kg = KeyGenerator.getInstance("DESede"); kg.init(168); SecretKey k = kg.generateKey(); byte[] ptext2 = k.getEncoded(); Socket socket = new Socket("127.0.0.1", 4421); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true); BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); //RSA算法,使用服务器端的公钥对DES的密钥进行加密 FileInputStream f3 = new FileInputStream("Skey_RSA_pub.dat"); ObjectInputStream b2 = new ObjectInputStream(f3); RSAPublicKey pbk = (RSAPublicKey) b2.readObject(); BigInteger e = pbk.getPublicExponent(); BigInteger n = pbk.getModulus(); BigInteger m = new BigInteger(ptext2); BigInteger c = m.modPow(e, n); String cs = c.toString(); out.println(cs); // 经过网络将加密后的秘钥传送到服务器 System.out.print("请输入待发送的数据:"); //用DES加密明文获得密文 String s = stdin.readLine(); // 从键盘读入待发送的数据 String postfix = MyBC.toPostfix(s); Cipher cp = Cipher.getInstance("DESede"); cp.init(Cipher.ENCRYPT_MODE, k); byte ptext[] = postfix.getBytes("UTF8"); byte ctext[] = cp.doFinal(ptext); String str = parseByte2HexStr(ctext); out.println(str); // 经过网络将密文传送到服务器 服务器解密、计算并发送至客户端部分的代码以下: String line = in.readLine(); BigInteger cipher = new BigInteger(line); 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();//mod n BigInteger m = cipher.modPow(d, n);//m=d (mod n) System.out.println("d= " + d); System.out.println("n= " + n); System.out.println("m= " + m); byte[] keykb = m.toByteArray(); // 使用DES对密文进行解密 String readline = in.readLine();//读取客户端传送来的数据 FileInputStream f2 = new FileInputStream("keykb1.dat"); int num2 = f2.available(); byte[] ctext = parseHexStr2Byte(readline); Key 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); //打印解密结果 NewMyDC evaluator = new NewMyDC(); int _result = evaluator.value(p); out.println("Echo:" + _result); out.close(); in.close(); link.close();
运行截图以下:
密钥分发结对编程:1人负责客户端,一人负责服务器
0.注意责任归宿,要会经过测试证实本身没有问题
1.基于Java Socket实现客户端/服务器功能,传输方式用TCP
2.客户端让用户输入中缀表达式,而后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密经过网络把密文发送给服务器
3.客户端和服务器用DH算法进行3DES或AES算法的密钥交换
4.服务器接收到后缀表达式表达式后,进行解密,而后调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
5.客户端显示服务器发送过来的结果
6.上传测试结果截图和码云连接
执行密钥协定的标准算法是DH算法(Diffie-Hellman算法),分为如下两步:
建立DH公钥和私钥;
建立共享密钥。
建立DH公钥和私钥:
实验体会与总结
本次实验是具体的网络编程,难度很大,按照同窗的博客一步步作才作完了实验,在作的过程当中也学到了许多知识点。
中缀表达式与后缀表达式
将运算符写在两个操做数中间的表达式
将运算符写在两个操做数以后的表达式
表达式求值算法:①中缀转后缀;②求后缀表达式的值
中缀转后缀的算法可描述为:
设置一个运算符栈,设置一个后缀表达式字符串;
从左到右依次对中缀表达式中的每一个字符ch分别进行如下处理,直至表达式结束:
若ch是左括号‘(’,将其入栈;
若ch是数字,将其后连续若干数字添加到后缀表达式字符串以后,并添加空格做为分隔符;
若ch是运算符,先将栈顶若干优先级高于ch的运算符出栈,添加到后缀表达式字符串以后,再将ch入栈。当‘(’运算符在栈中时,它的优先级最低。
若ch是‘)’,则若干运算符所有出栈,直到出栈的是左括号,一对括号匹配。
若表达式结束,将栈中运算符所有出栈,添加到后缀表达式字符串以后。
后缀表达式求值的算法可描述为(参考:娄老师的博客):
设置一个操做数栈,从左向右依次对后缀表达式字符串中的每一个字符ch进行处理;
若ch是数字,先将其后连续若干数字转化为整数,再将该整数入栈;
若ch是运算符,出栈两个值进行运算,运算结果再入栈;
重复以上步骤,直至后缀表达式结束,栈中最后一个数字就是所求表达式的值。
实现DES加密步骤:
对称密钥的生成和保存;
使用对称密钥进行加密和解密;
从文件中获取加密时使用的密钥,使用密钥进行解密;
RSA算法,使用服务器端的公钥对DES的密钥进行加密
KeyGenerator kg = KeyGenerator.getInstance("DESede"); kg.init(168); SecretKey k = kg.generateKey(); byte[] ptext2 = k.getEncoded(); Socket socket = new Socket("127.0.0.1", 4421); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true); BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); 用DES加密明文获得密文 FileInputStream f3 = new FileInputStream("Skey_RSA_pub.dat"); ObjectInputStream b2 = new ObjectInputStream(f3); RSAPublicKey pbk = (RSAPublicKey) b2.readObject(); BigInteger e = pbk.getPublicExponent(); BigInteger n = pbk.getModulus(); BigInteger m = new BigInteger(ptext2); BigInteger c = m.modPow(e, n); String cs = c.toString(); out.println(cs); // 经过网络将加密后的秘钥传送到服务器 System.out.print("请输入待发送的数据:");
MD5算法返回实现指定摘要算法的 MessageDigest对象:
String aline3 = in.readLine(); String x = p; MessageDigest m2 = MessageDigest.getInstance("MD5");