首先说一下,我这个网络版计算器要实现的效果,首先,我们由客户端输入要计算的公式,然后传递给服务器,进行计算,然后再返回给客户端计算结果。
首先会讲解一下我的代码大致的实现过程,然后会说一下中缀表达式转后缀表达式,最后附上代码。
第一步我们创建服务端,首先是创建ServerSocket对象,指定端口号,然后调用accept方法,等待客户机的接收,这里的话accept方法是阻塞式的,所谓的阻塞式就是说,accept方法它在等待客户机连接,如果没有客户机连接上来的话,那么他会一直在哪儿处于等待的状态,程序不会往下执行,然后创建一个字节输入流,读取由客户端发送过来的字符串。这里是部分代码。
ServerSocket ss = null;
Socket s = null;
InputStream ips = null;
DataInputStream dis = null;
OutputStream ops = null;
DataOutputStream dps = null;
try {
ss = new ServerSocket(6666);
while(true){
s = ss.accept();
System.out.println("a client connect");
ips = s.getInputStream();
dis = new DataInputStream(ips);
String s2 = dis.readUTF();
ops = s.getOutputStream();
dps = new DataOutputStream(ops);
try{
Long result = countAll_1(s2);
if(result == 0 && folmatFlag == true){
dps.writeUTF("您输入的格式有误");
dps.flush();
}else if(result == 0 && Doubleflag1 == true){
Double r = countAll_2(s2);
dps.writeUTF(r.toString());
dps.flush();
}else{
dps.writeUTF(result.toString());
dps.flush();
}
}catch(ArithmeticException ae){
ae.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
ss.close();
s.close();
ips.close();
dis.close();
ops.close();
dps.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
然后我们调用了一个方法,countAll(s2), 这里的这个方法就是我们将接收的字符串传递给这个方法,然后转换成数字进行计算,
代码如下:
public static long countAll_1(String s){
Stack<Character> ms = new Stack<>();
String[] s1 = new String[30];
int p1 = 0;
int p2 = -1;
int j = 0;
//1, 转为后缀表达式
for(int i = 0; i < s.length(); i++){
if(s.charAt(i) == '.'){
Doubleflag1 = true;
return (long)0;
}
if(decide(s.charAt(i))){
s1[j] = s.substring(p2+1, p1);
p2 = p1;
j++;
if(ms.isEmpty()){
ms.push(s.charAt(i));
}else if(ms.peek() == '('){
ms.push(s.charAt(i));
}else if(s.charAt(i) == ')'){
if(ms.peek() != '('){
s1[j] = ms.pop().toString();
j++;
}
ms.pop();
}else if((s.charAt(i) == '+' || s.charAt(i) == '-') && (ms.peek() == '*' || ms.peek() == '/')){
while(!ms.isEmpty()){
s1[j] = ms.pop().toString();
j++;
}
ms.push(s.charAt(i));
}else if((s.charAt(i) == '*' || s.charAt(i) == '/') && (ms.peek() == '+' || ms.peek() == '-')){
ms.push(s.charAt(i));
}else{
ms.push(s.charAt(i));
}
p1++;
}else if(decideNum(s.charAt(i))){
p1++;
}else{
folmatFlag = true;
return (long)0;
}
}
s1[j] = s.substring(s.length() - 1);
j++;
while(!ms.isEmpty()){
s1[j] = ms.pop().toString();
j++;
}
//2,计算
Long l = (long) 0;
Stack<String> ms2 = new Stack<>();
for(int i = 0; i < j; i++){
if(s1[i].equals("+")){
if(ms2.isEmpty())break;
l = Long.valueOf(ms2.pop()) + Long.valueOf(ms2.pop());
ms2.push(l.toString());
}else if(s1[i].equals("-")){
Long t1 = Long.valueOf(ms2.pop());
Long t2 = Long.valueOf(ms2.pop());
l = t2-t1;
ms2.push(l.toString());
}else if(s1[i].equals("*")){
l = Long.valueOf(ms2.pop()) * Long.valueOf(ms2.pop());
ms2.push(l.toString());
}else if(s1[i].equals("/")){
Long t3 = Long.valueOf(ms2.pop());
Long t4 = Long.valueOf(ms2.pop());
l = t4/t3;
ms2.push(l.toString());
}else if(s1[i].equals("")){
;
}else{
ms2.push(s1[i]);
}
}
return Long.valueOf(ms2.pop());
}
可以大致分为两步理解,因为在我们一般生活中都是用的中缀表达式,1,转后缀,2, 计算。
那么中缀表达式时如何转后缀表达式:
那么转成后缀过后,就再用一个栈,是数字就进栈,是符号就将栈顶的两个元素拿出来在运算,然后再再将运算结果进栈,注意的是,假如我们遇到减号,是3-2,是拿栈顶元素做被减数,除法也一样。然后最后返回栈里面的元素。
我这里面的decide方法是判断是不是基本运算的符号:+ - * / ( )
decideNum是判断是不是数字,如果不是,那么肯定就输入有问题。
然后还有一个判断有没有符号 " . ",有的话,就是小时运算,就另做处理。
追后返回运算结果就可以了。
然后再用一个输出流,返回给客户端就可以了。
客户端代码:
public static void main(String[] args){
Socket s = null;
DataOutputStream dos = null;
InputStream ips = null;
DataInputStream dips = null;
try{
s = new Socket("127.0.0.1", 6666);
OutputStream fos = null;
fos = s.getOutputStream();
System.out.println("请输入你想计算的公式:");
dos = new DataOutputStream(fos);
Scanner c = new Scanner(System.in);
String alls = c.nextLine();
dos.writeUTF(alls);
ips = s.getInputStream();
dips = new DataInputStream(ips);
String s3 = dips.readUTF();
System.out.println(s3);
}catch(IOException io){
io.printStackTrace();
}finally{
try {
dips.close();
dos.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}