20202324 實驗四 《數據結構與面向對象程序設計》實驗報告


# 20202324 2021-2022-1 《數據結構與面向對象程序設計》實驗報告

課程:《程序設計與數據結構》
班級: 2023
姓名:肖郅宇
學號:202023124
實驗教師:王志強
實驗日期:2021年10月12日
必修/選修: 必修

 

## 1.實驗內容

(一)Java Socket編程

1.學習藍墨雲上教材《Java和Android編程》“第16章 輸入/輸出 ”和“第22章 網絡”,學習JavaSocket編程
2.結對編程。結對伙伴A編寫客戶端SocketClient.java,結對伙伴B編寫服務器端。
3.截圖加學號水印上傳藍墨雲,代碼push到碼雲,並撰寫實驗報告。

(二)Java和密碼學

參考 http://www.cnblogs.com/rocedu/p/6683948.html

以結對的方式完成Java密碼學相關內容的學習(帖子中所有代碼和相關知識點需要學習)。提交學習成果碼雲鏈接和代表性成果截圖,要有學號水印。

(三)編寫有理數/復數計算器

結對編程,結對伙伴A編寫有理數計算器。結對伙伴B編寫復數計算器。截圖加水印上傳藍墨雲,代碼push碼雲。

(四)遠程有理數計算器

結對編程,結對伙伴A編程實現客戶端,結果伙伴B實現服務器端。
客戶端通過鍵盤輸入一個有理數計算的公式(例如:1/4 + 1/6 = ),並把該公式以字符串的形式發送給伙伴B(服務器端),服務器端根據字符串計算出結果為5/12,並把結果返回給客戶端A,A收到結果后輸出結果。截圖加水印上傳藍墨雲,代碼push碼雲。

(五)遠程復數計算器

結對編程,結對伙伴B編程實現客戶端,結果伙伴A實現服務器端。
客戶端通過鍵盤輸入一個有理數計算的公式(例如:1/4 + 1/6 = ),並把該公式以字符串的形式發送給伙伴A(服務器端),服務器端根據字符串計算出結果為5/12,並把結果返回給客戶端B,B收到結果后輸出結果。截圖加水印上傳藍墨雲,代碼push碼雲。

 

## 2.實驗過程及結果

(一)Java Socket編程

①服務器端

 

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Servertest {
public static void main(String[] args) throws IOException {
//1.建立一個服務器Socket(ServerSocket)綁定指定端口
ServerSocket serverSocket=new ServerSocket(2324);
//2.使用accept()方法阻止等待監聽,獲得新連接
Socket socket=serverSocket.accept();
//3.獲得輸入流
InputStream inputStream=socket.getInputStream();
BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream));
//獲得輸出流
OutputStream outputStream=socket.getOutputStream();
PrintWriter printWriter=new PrintWriter(outputStream);
//4.讀取用戶輸入信息
String info=null;
System.out.println("The Server has been established");
while(!((info = bufferedReader.readLine()) ==null)){
System.out.println("你猜猜我想說什么:" + info);
}
//給客戶一個響應
String reply="WUHUFLY!!!";
printWriter.write(reply);
printWriter.flush();
//5.關閉資源
printWriter.close();
outputStream.close();
bufferedReader.close();
inputStream.close();
socket.close();
serverSocket.close();
}
}

 

②客戶端

 

import java.io.*;
import java.net.Socket;
public class SocketClient {
public static void main(String[] args) throws IOException {
//1.建立客戶端Socket連接,指定服務器位置和端口
Socket socket = new Socket("172.16.43.44",2324);
//2.得到socket讀寫流
OutputStream outputStream = socket.getOutputStream();
PrintWriter printWriter = new PrintWriter(outputStream);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
//輸入流
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"GBK"));
//3.利用流按照一定的操作,對socket進行讀寫操作
String info1 = " 用戶名:Dogxzy,密碼:iamdog";
String info = new String(info1.getBytes("GBK"),"GBK");
printWriter.write(info);
printWriter.flush();
outputStreamWriter.write(info1);
outputStreamWriter.flush();
socket.shutdownOutput();
//接收服務器的響應
String reply = null;
while (!((reply = bufferedReader.readLine()) ==null)){
System.out.println("接收服務器的信息為:" + reply);
}
//4.關閉資源
bufferedReader.close();
inputStream.close();
outputStreamWriter.close();
//printWriter.close();
outputStream.close();
socket.close();
}
}


實驗成果截圖

 

 

 
 
        

 

 

 

 

 (三)編寫有理數/復數計算器

 實驗代碼

 復數類
import java.util.Scanner;
public class Plural extends Calculate{
    public static void main(String[] args) {
        String next = "y";
        String s;
        do{
            Scanner scan = new Scanner(System.in);
            System.out.println("請輸入復數運算式,各符號數字間用空格隔開,負數除外(如:( 1 + 2 i ) + ( 2 + -3 i ) ):");
            Calculate ff;
            ff = new Plural();
            s = scan.nextLine();
            ff.Faction(s);

            Calculate count;
            count = new Plural();

            switch (ch){
                case '+':
                {
                    count.Add();
                    break;
                }
                case '-':
                {
                    count.Sub();
                    break;
                }
                case '*':
                {
                    count.Mul();
                    break;
                }
                case '/':
                {
                    count.Div();
                    break;
                }
                default:
                    System.out.println("Illegal input!");
                    break;
            }

            System.out.println(count.toString(s));

            System.out.print("如果您想要繼續計算,請輸入y,否則輸入其他: ");
            choose = scan.nextLine();
        }while(choose.equals(next));
    }
}


分數類



import java.util.StringTokenizer;
public class fenshu {
    int fenzi,fenmu;
    char ch;

    public fenshu(String str) {
        StringTokenizer st=new StringTokenizer(str,"/",true);
        this.fenzi = Integer.parseInt(st.nextToken());
        this.ch=st.nextToken().charAt(0);
        this.fenmu = Integer.parseInt(st.nextToken());
    }

    public fenshu yuefen(int fz,int fm){
        int i;

        for (i=2;i<=fz&&i<=fm;i++){
            if(fz%i==0&&fm%i==0){
                fz=fz/i;
                fm=fm/i;
            }
        }

        fenshu result=new fenshu(fz+"/"+fm);
        return result;
    }

    public fenshu getJia(fenshu x){
        int newFenmu=this.fenmu*x.fenmu;
        int newFenzi=fenzi*x.fenmu+x.fenzi*fenmu;
        return yuefen(newFenzi,newFenmu);
    }

    public fenshu getJian(fenshu x){
        int newFenmu=fenmu*x.fenmu;
        int newFenzi=fenzi*x.fenmu-x.fenzi*fenmu;
        return yuefen(newFenzi,newFenmu);
    }

    public fenshu getCheng(fenshu x){
        int newFenmu=fenmu*x.fenmu;
        int newFenzi=fenzi*x.fenzi;
        return yuefen(newFenzi,newFenmu);
    }

    public fenshu getChu(fenshu x){
        int newFenmu=fenmu*x.fenzi;
        int newFenzi=fenzi*x.fenmu;
        return yuefen(newFenzi,newFenmu);
    }

    @Override
    public String toString() {
        return fenzi + "/" + fenmu;
    }

}

有理數計算器
public class RationalNumberCalculator {
    public static void main(String[] args) {

        fenshu result;
        fenshu fenshu1;
        if(args[0].contains("/")){
            fenshu1=new fenshu(args[0]);
        }
        else{
            fenshu1=new fenshu(args[0]+"/"+1);
        }

        fenshu fenshu2;
        if(args[2].contains("/")){
            fenshu2=new fenshu(args[2]);
        }
        else{
            fenshu2=new fenshu(args[2]+"/"+1);
        }

        char ch=args[1].charAt(0);


        switch (ch)
        {
            case '+':
                result=fenshu1.getJia(fenshu2);
                System.out.println(fenshu1+String.valueOf(ch)+fenshu2+"="+result);
                break;
            case '-':
                result=fenshu1.getJian(fenshu2);
                System.out.println(fenshu1+String.valueOf(ch)+fenshu2+"="+result);
                break;
            case '*':
                result=fenshu1.getCheng(fenshu2);
                System.out.println(fenshu1+String.valueOf(ch)+fenshu2+"="+result);
                break;
            case '/':
                result=fenshu1.getChu(fenshu2);
                System.out.println(fenshu1+String.valueOf(ch)+fenshu2+"="+result);
                break;
            default:
                System.out.println("Illegal input!");
                break;
        }
    }
}


復數計算器


import java.util.StringTokenizer;

public abstract class Calculate {
    static double a,b,c,d;
    double RealPart;
    double ImagePart;
    static String choose;
    public static char ch;

    public void Add() {
        RealPart = a + c;
        ImagePart = b + d;
    }

    public void Sub() {
        RealPart = a - c;
        ImagePart = b - d;
    }

    public void Mul() {
        RealPart = a*c - b*d;
        ImagePart = b*c + a*d;
    }

    public void Div() {
        RealPart = (a*c + b*d)/(c*c + d*d);
        ImagePart = (b*c + a*d)/(c*c + d*d);
    }

    public String toString(String s) {
        if(ImagePart >= 0){
            return s + "=" + RealPart + "+" + ImagePart + "i";
        }else {
            return s + "=" + RealPart +""+ ImagePart + "i";
        }
    }

    public void Faction(String f){
        char z;                                //取出不用於計算的符號
        StringTokenizer st = new StringTokenizer(f, " ", false);
        z = st.nextToken().charAt(0);
        a = Double.parseDouble(st.nextToken());
        z = st.nextToken().charAt(0);
        b = Double.parseDouble(st.nextToken());
        z = st.nextToken().charAt(0);
        z = st.nextToken().charAt(0);
        ch = st.nextToken().charAt(0);
        z = st.nextToken().charAt(0);
        c = Double.parseDouble(st.nextToken());
        z = st.nextToken().charAt(0);
        d = Double.parseDouble(st.nextToken());
    }
}

(四)遠程有理數計算器

 實驗代碼

①服務器端
import java.io.*;
import java.net.ServerSocket;
import java.net.*;
import java.util.StringTokenizer;
public class server2 {
private static fenshu frac2;
private static fenshu frac1;
private static String a,b;
private static char ch;
private static fenshu result = null;

public static void main(String[] args) throws IOException {
//1.建立一個服務器Socket(ServerSocket)綁定指定端口
ServerSocket serverSocket=new ServerSocket(2324);
//2.使用accept()方法阻止等待監聽,獲得新連接
Socket socket=serverSocket.accept();
//3.獲得輸入流
InputStream inputStream=socket.getInputStream();
BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream));
//獲得輸出流
OutputStream outputStream=socket.getOutputStream();
PrintWriter printWriter=new PrintWriter(outputStream);
//4.讀取用戶輸入信息
String info=null;
System.out.println("The server has been Established by xzy or wxy");
while(!((info = bufferedReader.readLine()) ==null)){
System.out.println("猜猜我要說什么,用戶的加密信息為:"+ info);
String s= info;
String es="";
int key = -4;
for(int i=0;i<s.length( );i++)
{ char c=s.charAt(i);
if(c>=0 && c<=127) // 是小寫字母
{ c+=key%26; //移動key%26
if(c<0) c+=127; //向左超界
if(c>127) c-=127; //向右超界
}

es+=c;
}

System.out.println("沒想到吧,用戶的解密后的信息竟然是:" + es);
StringTokenizer st = new StringTokenizer(es, " ", false);
a=st.nextToken();
ch=st.nextToken().charAt(0);
b=st.nextToken();
frac1=new fenshu(a);
frac2=new fenshu(b);

switch (ch)
{
case '+':
result=frac1.getJia(frac2);

break;
case '-':
result=frac1.getJian(frac2);

break;
case '*':
result=frac1.getCheng(frac2);

break;
case '/':
result=frac1.getChu(frac2);

break;
default:

break;
}
}
//給客戶一個響應
String reply=frac1+String.valueOf(ch)+frac2+"="+result;
String z= reply;
String tes="";
int key = 4;
for(int j=0;j<z.length( );j++)
{ char d=z.charAt(j);
if(d>=0 && d<=127) // 是小寫字母
{ d+=key%26; //移動key%26
if(d<0) d+=127; //向左超界
if(d>127) d-=127; //向右超界
}

tes+=d;
}
printWriter.write(tes);
printWriter.flush();
//5.關閉資源
printWriter.close();
outputStream.close();
bufferedReader.close();
inputStream.close();
socket.close();
serverSocket.close();
}
}
②客戶端
import java.io.*;
import java.net.*;
public class client2 {
public static void main(String[] args) throws IOException {
//1.建立客戶端Socket連接,指定服務器位置和端口
Socket socket = new Socket("172.20.10.8",2324);
// Socket socket = new Socket("172.16.43.187",8800);

//2.得到socket讀寫流
OutputStream outputStream = socket.getOutputStream();
// PrintWriter printWriter = new PrintWriter(outputStream);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
//輸入流
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));
//3.利用流按照一定的操作,對socket進行讀寫操作
String info1 = " 1/4 + 1/6";
String z= info1;
String tes="";
int key = 4;
for(int j=0;j<z.length( );j++)
{ char d=z.charAt(j);
if(d>=0 && d<=127) // 是小寫字母
{ d+=key%26; //移動key%26
if(d<0) d+=127; //向左超界
if(d>127) d-=127; //向右超界
}

tes+=d;
}
// String info = new String(info1.getBytes("GBK"),"utf-8");
// printWriter.write(info);
// printWriter.flush();
outputStreamWriter.write(tes);
outputStreamWriter.flush();
socket.shutdownOutput();
//接收服務器的響應
String reply = null;
while (!((reply = bufferedReader.readLine()) ==null)){
System.out.println("接收到的服務器信息居然是"+ reply);
String s= reply;
String es="";
key = -4;
for(int i=0;i<s.length( );i++)
{ char c=s.charAt(i);
if(c>=0 && c<=127) // 是小寫字母
{ c+=key%26; //移動key%26
if(c<0) c+=127; //向左超界
if(c>127) c-=127; //向右超界
}

es+=c;
}
System.out.println("結果最后接收服務器的信息明文為:" + es);
}
//4.關閉資源
bufferedReader.close();
inputStream.close();
outputStreamWriter.close();
//printWriter.close();
outputStream.close();
socket.close();
}
}
實驗成果截圖


 

 

 

 


(五)遠程復數計算器

實驗代碼

①服務器端

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class serverComplex extends Calculate{
public static void main(String[] args) throws IOException {
//建立服務器綁定窗口
ServerSocket serverSocket = new ServerSocket(2324);
//accept()方法處理連接請求,防止非法監聽
Socket socket = serverSocket.accept();
//輸入流
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
//輸出流
OutputStream outputStream = socket.getOutputStream();
PrintWriter printWriter = new PrintWriter(outputStream);
//讀取用戶信息
String info = null;
System.out.println("The server is working...");
//反饋信息
while (!((info=bufferedReader.readLine())==null)) {
System.out.println("我是超級xzy,接受的加密信息為:" + info);
int key = -4; //取命令行參數的第二個字符,即密鑰,並將其轉為整型
String es = ""; //創建接收密文的字符串變量並初始化
for (int i = 0; i < info.length(); i++) { //逐一對明文字符進行加密
char c = info.charAt(i);
if (c >= 'a' && c <= 'z') // 是小寫字母
{
c += key % 26; //移動key%26
if (c < 'a') c += 26; //向左超界
if (c > 'z') c -= 26; //向右超界
} else if (c >= '0' && c <= '9') // 是數字
{
c += key % 10;
if (c < '0') c += 10;
if (c > '9') c -= 10;
} else if (c >= '*' && c <= '/') {
c += key % 6;
if (c < '*') c += 6;
if (c > '/') c -= 6;
}
es += c;
}
System.out.println("笑死我了解密后的信息為:" + es);

Calculate ff;
ff = new serverComplex();
ff.Faction(es);

Calculate count;
count = new serverComplex();

switch (ch){case '+':
{
count.Add();
break;
}
case '-':
{
count.Sub();
break;
}
case '*':
{
count.Mul();
break;
}
case '/':
{
count.Div();
break;
}
}

String reply = count.toString(es);

//傳遞信息
printWriter.write(reply);
printWriter.flush();
//關閉資源
inputStream.close();
outputStream.close();
bufferedReader.close();
printWriter.close();
serverSocket.close();
socket.close();
}
}
}


②客戶端
import java.io.*;
import java.net.Socket;

public class ClientComplex {
public static void main(String[] args) throws IOException {
//建立客戶端,host為伙伴的IP地址
Socket socket = new Socket("172.20.10.8",2324);
//輸入流
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"GBK"));
//輸出流,獲取socket讀寫流
OutputStream outputStream = socket.getOutputStream();
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
//利用流按照一定的操作,傳遞信息,對socket進行讀寫操作
String s= "( 1 + 2 i ) + ( 1 + -2 i )"; //取命令行參數的第一個字符,即需要加密的明文
int key=4; //取命令行參數的第二個字符,即密鑰,並將其轉為整型
String es=""; //創建接收密文的字符串變量並初始化
for(int i=0;i<s.length( );i++){ //逐一對明文字符進行加密
char c=s.charAt(i);
if(c>='a' && c<='z') // 是小寫字母
{
c+=key%26; //移動key%26
if(c<'a') c+=26; //向左超界
if(c>'z') c-=26; //向右超界
}
else if(c>='0' && c<='9') // 是數字
{
c+=key%10;
if(c<'0') c+=10;
if(c>'9') c-=10;
}
else if(c>='*' && c<='/')
{
c+=key%6;
if(c<'*') c+=6;
if(c>'/') c-=6;
}
es+=c;
}

System.out.println(es);
String info1 = es;
outputStreamWriter.write(info1);
outputStreamWriter.flush();
socket.shutdownOutput();
//接受響應
String reply = null;
while (!((reply = bufferedReader.readLine())==null)){
System.out.println(reply);
}
//關閉資源
bufferedReader.close();
inputStream.close();
outputStreamWriter.close();
outputStream.close();
}
}

實驗成果截圖

 

 

 

 

 

 

## 3. 實驗過程中遇到的問題和解決過程

- 問題1:服務器啟動后客戶端無法連接
- 問題1解決方案:各種方法搞定,接口、ip、校園網不行換成手機熱點等等
- 問題2:輸出的文字都是亂碼
- 問題2解決方案:切換為GBK后解決,

 
        

 

 
        

 

 
        


## 其他(感悟、思考等)
太難了,不想再搞這么難的實驗了。。。

 

不過還好每一個問題解決的時間都不長,只是代碼量大到驚人而已,而已。

密碼學的那個實在是搞不懂,就這樣下班吧。

 

 

 希望下一個實驗簡單點。





 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM