1. 程式人生 > 資料庫 >SOCKET編寫客戶端和服務端通訊,連線Mysql資料庫,java實現動態監控

SOCKET編寫客戶端和服務端通訊,連線Mysql資料庫,java實現動態監控

詳細課設報告以及 C#、java 原始碼見
碼雲: https://gitee.com/xyy9/socket
github: https://github.com/XYYhub/socket
建立資料庫略過

C#連線資料庫

需要新增MySql.Data.dll引用連線資料庫
內碼表新增using MySql.Data.MySqlClient

string str = "server=localhost; User Id=root; password=root; Database=server";
//連線MySQL的字串
MySqlConnection mycon = new MySqlConnection(str);//例項化連結
mycon.Open();//開啟連線
MySqlCommand mycmd = new MySqlCommand("insert into tcp(type,id,sn,power,state,time) values('" + type1 + "','" + id1 + "','" + sn1 + "','" + power1 + "','" + state1 + "','" + time1 + "')",mycon);
if (mycmd.ExecuteNonQuery() > 0)
{
    Console.WriteLine("資料插入成功!");
}
 mycon.Close();//關閉

服務端和客戶端的雙向通訊

服務端和客戶端的雙向通訊,在基於服務端接收完客戶端的資訊後,需要向客戶端傳送反饋資訊,以告知客戶端,資訊已經成功被接收,建立此反向通訊機制後,也可通過從服務端傳送相關控制資訊給客戶端,來對客戶端進行相關操作。

服務端傳送簡單反饋資訊

在服務端接收完畢客戶端資料,並將資料存入資料庫成功後。服務端開始傳送反饋資訊
1、服務端傳送:
byte[] dataToC = System.Text.Encoding.ASCII.GetBytes(“Received successfully”);
handler.Send(dataToC);

2、客戶端接收:
byte[] bytes = new Byte[1024];

int bytesRec = clientSocket.Receive(bytes);
string dataBack = Encoding.ASCII.GetString(bytes,bytesRec);
Console.WriteLine(dataBack);
就此即可完成服務端的自定義語句,在客戶端接收並顯示。

3.設計思想:
在服務端建立控制開關機制,以判斷向客戶端傳輸的具體反饋資訊,客戶端根據收到的反饋資訊判斷具體的執行任務。

服務端控制函式:
初步採用命令臺內,鍵盤輸入進行控制,在每一次迴圈建立埠監聽時,都進行對鍵盤的監聽,鍵盤輸入相應的終止按鍵,則switch語句便執行相應的終止語句,否則預設跳出判斷語句。以下為相應程式碼。

//非阻塞式監聽鍵盤輸入
if (Console.KeyAvailable)
{
    ConsoleKeyInfo key = Console.ReadKey(true);
    switch (key.Key)
    {
        case ConsoleKey.F2:
            Console.WriteLine("You pressed F2!");
            byte[] data = System.Text.Encoding.ASCII.GetBytes("ShutDown");
            handler.Send(data);
            break;
        default:
            break;
    }
}
客戶端判斷函式:
if (dataBack == "ShutDown")
{
    clientSocket.Close();
}

進一步優化:
為便於連線GUI控制,應將判斷內容改為具體的某一個變數,而非對鍵盤輸入的監聽,在服務端與客戶端都應以語句中的state的值為“on”或“off”來控制客戶端的狀態。

利用JAVA和MySQL實現資料的動態實時監控

設計思想:在服務端分割資訊存入資料庫後,用JAVA連線資料庫,運用JfreeChart實現裝置電壓變化的視覺化以及動態更新。
主要步驟如下:

設計DBUtil工具類模組。

用於連線Mysql資料庫。
主要程式碼如下:

Connection conn = null;
Class.forName("com.mysql.cj.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/server?serverTimezone=UTC";
			String username = "root";
			String password = "******";
			conn = DriverManager.getConnection(url,username,password);

幷包裹try/catch異常獲取,列印錯誤提示以及錯誤資訊。

設計Entity模組,

用於創造儲存Mysql中每條資料的類,並構造get函式用於獲取確定資訊,構造set函式用於設定或者修改具體資訊。
類內的具體屬性值如以下程式碼,一一對應於資訊傳遞中規定的資訊格式,即資料庫中的資料格式,全部定義為String字串型別。為了避免外部的隨意干涉,設定為private私有屬性。

public class Entity {
	private String type;
	private String id;
	private String sn;
	private String power;
	public String state;
	private String time;
為了方便對類內的屬性進行獲取和設定,需要對每個屬性都構造get以及set函式,以下為Type屬性的get以及set函式,其餘省略,不再贅述。
	public String getType() {
		return type;
	}
	public void setType(String type) {
		this.type = type;
		}
		…………
}

設計DAO模組

用於構造各類與資料庫相關的功能函式,比如getAll() 獲取資料庫中的全部資料,getTen() 獲取資料庫中最新的十條資料,以及update() 修改函式,用於修改資料庫中的某條資料。
以下為主要原始碼,因為獲取的結果為多個類,所以設定獲取函式的型別為java中的ArrayList陣列連結串列,此函式既擁有陣列的特性,也擁有連結串列的特性,極為方便。

	public ArrayList<Entity> getAll(){
		ArrayList<Entity> ar = new ArrayList<Entity>();

設定conn呼叫DBUtil中的連線資料庫函式,ps為執行語句函式,rs為結果存放函式。

		Connection conn = DBUtil.getConnection();
		PreparedStatement ps = null;
		ResultSet rs = null;
設定sql語句如下,並執行,且存放執行結果。
		String sql = "select type,time from tcp";
			ps = conn.prepareStatement(sql);
			rs = ps.executeQuery();

以while迴圈不斷呼叫Entity中的set函式,儲存獲取的資料庫資訊至新建的ArrayList類中。

			while(rs.next()) {
				Entity ent = new Entity();
				ent.setType(rs.getString("type"));
				ent.setId(rs.getString("id"));
				ent.setSn(rs.getString("sn"));
				ent.setPower(rs.getString("power"));
				ent.setState(rs.getString("state"));
				ent.setTime(rs.getString("time"));
				ar.add(ent);
			}

至此資料全部儲存在ArrayList ar中。最後return ar函式即可獲得結果。需要注意的是一定要記得釋放rs、ps、conn三個函式,並且注意要依次釋放。
將SQL語句改為

"select * from tcp Order By time Desc limit 10"

即可編寫獲取最新的十個資料的功能函式 getTen(),為了給gui控制介面做準備,也寫了一個修改函式update,用以從java更改資料庫中的某個ID的裝置的狀態,以進行開啟和關閉操作,具體仍有待實現,此為java資料庫介面,主要原始碼如下:

String sql = "UPDATE tcp SET state= ? WHERE id=?";
			ps = conn.prepareStatement(sql);
			ps.setString(1,ent.getState());

設計Charts模組

用於將資料通過JfreeChart實現資料庫中的資訊視覺化,繪製成折線圖顯示近十條資料的變化趨勢。並構造定時器,實現每隔一秒動態重新整理,重新獲取最新的十條資料庫內資料。
JFreeChart是JAVA平臺上的一個開放的圖表繪製類庫。它完全使用JAVA語言編寫,是為applications,applets,servlets 以及JSP等使用所設計。JFreeChart可生成餅圖(pie charts)、柱狀圖(bar charts)、散點圖(scatter plots)、時序圖(time series)、甘特圖(Gantt charts)等等多種圖表,並且可以產生PNG和JPEG格式的輸出。
本次我們使用它的折線圖繪製。要使用JfreeChart需要官網下載Jcommon以及JfreeChart兩個包,目前最新的包為jcommon-1.0.23.jar以及jfreechart-1.0.19.jar下載完畢後匯入工程,並構造路徑,即可使用JfreeChart。

通過StandardChartTheme 可以設定Chart的外觀格式,如字型大小等。

StandardChartTheme mChartTheme = new StandardChartTheme("CN");
        mChartTheme.setLargeFont(new Font("黑體",Font.BOLD,20));
        mChartTheme.setExtraLargeFont(new Font("宋體",Font.PLAIN,15));
    mChartTheme.setRegularFont(new Font("宋體",15));

通過for迴圈依次設定折線圖的資料集。

ArrayList<Entity> ar=new DAO().getTen();
        int index = ar.size()-1;
		for(Entity ne; index>=0 ;index--) {
			ne = ar.get(index);
			mDataset.addValue(Double.valueOf(ne.getPower()),"裝置"+ne.getId(),ne.getTime().split(" ")[1]);
		}

新建折線圖,設定表標題及x軸y軸及其他相關資訊。

JFreeChart mChart = ChartFactory.createLineChart(
                "電壓波動折線圖",//圖名字
                "時間",//橫座標
                "電壓",//縱座標
                mDataset,//資料集
                PlotOrientation.VERTICAL,true,// 顯示圖例
                true,// 採用標準生成器
            false);// 是否生成超連結

最終實現以下畫面4.22,以電壓為縱座標,時間每秒為橫座標,顯示電壓波動狀況。

動態折線圖

將資料集設定函式放置在while無限迴圈中,並設定執行緒休眠1000ms,以實現每秒動態更新折線圖。

while(true){
    mPlot.setDataset(GetDataset());
Thread.sleep(1000);
	}

遇到的問題

在動態實現java折線圖顯示最新的十條資料的時候,由於SQL語句為
select * from tcp Order By time Desc limit 10
即將資料按時間順序倒序排序,並輸出前十個,這導致了越新的資料會儲存在陣列的越前面,使輸出繪製折線圖的時候,最新的資料顯示在了折線圖的左側,整個折線圖動態更新時,會整體從左向右移動,這不符合傳統的使用者使用邏輯,所以需要對從資料庫中提取出的資料,在賦值給折線圖資料集時,進行逆序操作。具體更改如下:

原始碼:

ArrayList<Entity> ar=new DAO().getTen();
		for(Entity ne:ar) {
mDataset.addValue(Double.valueOf(ne.getPower()),ne.getTime().split(" ")[1]);
}

更改後代碼:

ArrayList<Entity> ar=new DAO().getTen();
        int index = ar.size()-1;
		for(Entity ne; index>=0 ;index--) {
			ne = ar.get(index);
mDataset.addValue(Double.valueOf(ne.getPower()),ne.getTime().split(" ")[1]);
		}

先用size()獲取陣列大小,再以for迴圈依次從陣列最末尾依次遞減,進行資料集新增。更改後實現了動態重新整理的方向更改。