反叛之冰:ZeroC ICE基礎使用
1 系統環境
系統:Win7。
版本:JDK 1.8.0_91,ZeroC ICE 3.6.3。
2 基礎
視訊教程:https://www.chuanke.com/v6242976-184547-1010808.html
書籍:ZeroC Ice權威指南 高清 帶索引書籤目錄 leader-us(著)
2.1 ICE基礎
2.2 Slice
2.2.1 基本資料型別
型別 |
定義及範圍 |
長度 |
bool |
true of false |
≥ 1bit |
byte |
[-128, 127] or [0, 255] |
≥ 8bit |
short |
[-2^15, 2^15-1] |
≥ 16bit |
int |
[-2^31, 2^31-1] |
≥ 32bit |
long |
[-2^63, 2^63-1] |
≥ 64bit |
float |
|
≥ 32bit |
double |
|
≥ 64bit |
string |
|
variable-length |
2.2.2 常量定義
用const修飾,如:
const bool trueOrFalse = true;
const byte b = 0x0f;
const string msg = “hello”;
const short s = 56;
const double PI = 3.1416;
enum Fruit {Apple, Orange}; (enum型別其實等價於int)
const Fruit favoriteFruit = Orange;
2.2.3 複合資料結構定義
型別 |
含義說明 |
enum |
列舉,如: enum Fruit {Apple, Orange} 或: enum Fruit {Apple = 5, Orange = 1} 實際上enum型別等價於int |
struct |
結構體,保護多個屬性資料,類似與JavaBean。 struct Student { int id; string name; } |
sequence |
複合型別,支援 基本型別的集合 或者 複合型別的集合,如: sequence<Fruit> FruitPlatter; sequence<FruitPlatter> FruitBanquet; (集合的集合) |
dictionary |
Map型別,類似於Java HashMap,如: dictionary<long, Student> StudentMap |
例:
struct TimeOfDay {
shor hour; // 0 - 23
shor minute; // 0 - 59
shor second; // 0 - 59
};
2.2.4 異常定義
exception Error {}; // 可定義空異常
exception RangeError {
TimeOfDay errorTime;
TimeOfDay minTime;
TimeOfDay maxTime;
};
2.2.5 slice檔案複用
使用#include關鍵字可引用其他slice檔案:
#include common.slice
2.2.6 介面和方法定義
使用interface來申明介面(語法上跟java定義介面語法類似,只是沒有public關鍵字),如:
interface Clock {
TimeOfDay getTime();
void setTime(TimeOfDay time);
}
Idempotent關鍵詞:用該關鍵詞修飾方法,指明該方法是冪等的,即呼叫1次和呼叫2次其結果是一樣的。新增Idempotent修飾的方法,可以讓ICE更好地實現“自動恢復錯誤”機制,即在某個Ice Object呼叫失敗的情況下,ICE會再次呼叫有Idempotent修飾的方法,透明恢復故障,而在客戶端看來則呼叫正常,沒有感覺到ICE做了自動故障恢復操作。
3 例項
參考:http://blog.csdn.net/xuzheng_java/article/details/24459181
所需jar包:
ICE安裝目錄下lib目錄裡的ice-3.6.3.jar
3.1 Slice指令碼
HelloWorldIDL.ice
[["java:package:myice.demo"]]
HelloWorldIDL.ice
[["java:package:myice.demo"]]
module test {
interface HelloWorldIDL {
string sayHello(string username);
};
};
說明:
Ø slice檔案必須以ice為字尾。
Ø [["java:package:myice.demo"]]定義java父包路徑,module表示模組名,真正生成的包路徑為myice.demo.test。
Ø module定義不能缺少。
Ø 在定義語句的結尾(如右花括號)需要以分號結尾。
3.2 生成通用服務類
slice2java--output-dir D:\iceoutput D:\slice\HelloWorldIDL.ice
3.3 Server端編寫服務實現類
Ø HelloWorldHandler.java
package server;
import Ice.Current;
import myice.demo.test._HelloWorldIDLDisp;
/**
* 介面處理類,繼承生成的_HelloWorldIDLDisp類
*/
public class HelloWorldHandler extends _HelloWorldIDLDisp {
private static final long serialVersionUID = 1L;
/*
* 在__current.ctx裡可獲取到客戶端額外上送的引數
*/
@Override
public String sayHello(String username, Current __current) {
return "Hello ZeroC ICE, [" + username + "]";
}
}
Ø HelloIceHandler.java
package server;
import Ice.Current;
import myice.demo.test._HelloWorldIDLDisp;
/**
* 介面處理類,繼承生成的_HelloWorldIDLDisp類
*/
public class HelloIceHandler extends _HelloWorldIDLDisp {
private static final long serialVersionUID = 1L;
/*
* 在__current.ctx裡可獲取到客戶端額外上送的引數
*/
@Override
public String sayHello(String username, Current __current) {
return "Hello ICE ASDFSDF, [" + username + "]";
}
}
3.4 Server端註冊服務並監聽請求
package server;
public class HelloWorldServer {
public static void main(String[] args) {
Ice.Communicator communicator = null;
try {
// 初始化ICE Communicator物件,args可以傳一些初始化引數,如連線超時、初始化客戶端連線池數量等
communicator = Ice.Util.initialize(args);
// 建立ObjectAdapter(名稱為helloWorldAdapter),使用預設的通訊協議(TCP/IP),埠為7890,用於監聽請求
Ice.ObjectAdapter adapter = communicator.createObjectAdapterWithEndpoints("helloWorldAdapter", "default -p 7890");
// 建立服務端介面處理handler例項(ice裡稱為servant)
HelloWorldHandler helloWorldHandler = new HelloWorldHandler();
/*
* 將helloWorldHandler新增到ObjectAdapter中,並將helloWorldHandler關聯到ID為"helloWorldHandler"的Ice Object
* (此處ID相當於介面名稱,全域性唯一,client端通過該名稱連線上來)
*/
adapter.add(helloWorldHandler, Ice.Util.stringToIdentity("helloWorldHandler"));
adapter.activate(); // 啟用ObjectAdapter
// 在服務退出前,一直監聽請求
communicator.waitForShutdown();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (communicator != null) {
communicator.destroy();
}
}
}
}
3.5 Client傳送請求並得到響應
package client;
import myice.demo.test.HelloWorldIDLPrx;
import myice.demo.test.HelloWorldIDLPrxHelper;
public class HelloWorldClient {
public static void main(String[] args) {
Ice.Communicator communicator = null;
try {
// 初始化ICE Communicator物件,args可以傳一些初始化引數,如連線超時、初始化客戶端連線池數量等
communicator = Ice.Util.initialize(args);
// 傳入遠端服務介面的名稱、網路協議、IP和埠,建立一個Proxy物件
Ice.ObjectPrx base = communicator.stringToProxy("helloWorldHandler:default -p 7890");
/*
* 通過checkedCast向下轉型,獲取HelloWorld介面的代理類(客戶端)
* 其中:HelloWorldIDLPrx和HelloWorldIDLPrxHelper為生成的類
*/
HelloWorldIDLPrx helloWorldClient = HelloWorldIDLPrxHelper.checkedCast(base);
if (helloWorldClient != null) {
String result = helloWorldClient.sayHello("ZEROC ICE");
// 可額外傳參到服務端,服務端在Current的ctx屬性裡可獲取到傳參值。如:
// Map<String, String> params = new HashMap<String, String>();
// params.put("param1", "aaaaaaa");
// params.put("param2", "bbbbbbb");
// String result = helloWorldClient.sayHello("ZEROC ICE", params);
System.out.println(result);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (communicator != null) {
communicator.destroy();
}
}
}
}
3.6 執行
執行HelloWorldServer,啟動服務。
執行HelloWorldClient,呼叫遠端服務介面,控制檯列印如下:
Hello ZeroC ICE, [ZEROC ICE]
成功呼叫遠端服務。
4 IceBox
IceBox類似於Tomcat,裡面可以載入多個伺服器例項(應用)。本章節示範一個IceBox容器的開發過程。
所需jar包:icebox-3.6.3.jar
4.1 伺服器例項編寫
一個IceBox伺服器例項繼承自IceBox.Service介面:
package icebox;
import Ice.Communicator;
import IceBox.Service;
import server.HelloIceHandler;
import server.HelloWorldHandler;
/**
* IceBox伺服器例項,實現IceBox.Service介面
*/
public class HelloWorldServer2 implements Service {
private Ice.ObjectAdapter adapter = null;
@Override
public void start(String name, Communicator communicator, String[] arg2) {
System.out.println("ice box helloworld starting...");
adapter = communicator.createObjectAdapter(name);
// 建立服務端介面處理handler例項(ice裡稱為servant)
HelloWorldHandler helloWorldHandler = new HelloWorldHandler();
HelloIceHandler helloIceHandler = new HelloIceHandler();
// 將Handler新增到ObjectAdapter中
adapter.add(helloWorldHandler, Ice.Util.stringToIdentity("helloWorldHandler2"));
adapter.add(helloIceHandler, Ice.Util.stringToIdentity("helloIceHandler2"));
adapter.activate(); // 啟用ObjectAdapter
System.out.println("ice box helloworld started.");
}
@Override
public void stop() {
adapter.destroy();
System.out.println("ice box helloworld stoped.");
}
}
4.2 配置檔案編寫
編寫icebox.properties配置檔案,建議放在classpath裡,示例配置如下:
#icebox instance properties begin
IceBox.InstanceName=MyIceBox 1
IceBox.InheritProperties=1
IceBox.PrintServicesReady=MyAppIceBox 1
#icebox instance properties end
#log define begin
Ice.Trace.Network=1
Ice.Trace.ThreadPool=1
Ice.Trace.Locator=1
#log define end
#server define begin
IceBox.Service.HelloWorldServer2=icebox.HelloWorldServer2 prop1=1 prop2=2 prop3=3
IceBox.UseSharedCommunicator.HelloWorldServer2=1
HelloWorldServer2.Endpoints=tcp -h localhost -p 7890
#server define end
4.3 執行
4.3.1 啟動IceBox容器
Ø 在eclipse裡除錯
執行IceBox容器,可通過java命令執行,也可在eclipse裡除錯:
在專案上右擊->Debug As->Debug configurations,新建一個debugconfiguration,配置資訊如下:
Main->Name:根據需要填寫,如IceBoxTest
Main->MainClass:IceBox.Server
Arguments->program arguments:--Ice.Config=icebox.properties
點選debug按鈕,即可啟動MainClass進行除錯。
Ø 通過程式碼啟動
package icebox;
public class StartIceBox {
public static void main(String[] args) {
IceBox.Server icebox = new IceBox.Server();
icebox.main(new String[] {"--Ice.Config=icebox.properties"});
}
}
4.3.2 執行客戶端
執行章節3.5即可。
5 IceGrid
IceGrid為ICE提供的分散式系統架構,由一個Ice Registry + N個Ice Grid Node組成。
5.1 Ice Registry
Ice Registry(登錄檔)元件用於儲存服務的Endpoint資訊,支援主從同步,從節點可以分擔查詢請求,類似MySQL的讀寫分離,並防止單點故障。Registry以二進位制檔案形式儲存執行期Ice服務註冊資訊。
IceBox可以註冊到Registry上,客戶端通過向Registry傳送請求,得到具體的服務的Endpoint資訊,然後建立起服務之間的直連TCP通道,此後的資料互動就在這個直連通道上完成。
本節示例配置一個Registry元件,並註冊一個IceBox服務到Registry上,編寫客戶端通過該Registry來訪問服務,此處Registry僅提供查詢服務的功能。
5.1.1 啟動Registry
Ø 配置檔案
編寫配置檔案:icegridregistry.cfg
IceGrid.InstanceName=MyIceGrid #預設名稱是IceGrid
IceGrid.Registry.Client.Endpoints=tcp -h 192.168.1.7 -p 4061
IceGrid.Registry.Server.Endpoints=tcp -h 192.168.1.7
IceGrid.Registry.Internal.Endpoints=tcp -h 192.168.1.7
IceGrid.Registry.Data=D:\Program Files (x86)\ZeroC\data\registry #路徑需手動建立好
IceGrid.Registry.PermissionsVerifier=MyIceGrid/NullPermissionsVerifier
IceGrid.Registry.AdminPermissionsVerifier=MyIceGrid/NullPermissionsVerifier
IceGrid.Registry.DynamicRegistration=1
Ø 啟動
進入ice安裝目錄下的bin子目錄,啟動registry,如:
D:\Program Files (x86)\ZeroC\Ice-3.6.3\bin>
icegridregistry --Ice.Config=D:\ZerocICE\publish\rsrc\icegridregistry.cfg
啟動後,可在IceGrid.Registry.Data目錄下看到生成的一堆二進位制檔案。
5.1.2 註冊IceBox到Registry
註冊IceBox到Registry,只需在原有的IceBox配置檔案(4.1)上新增如下配置,啟動IceBox即可:
#iceboxregistry define begin
Ice.Default.Locator=MyIceGrid/Locator:tcp -h 192.168.1.7 -p 4061
HelloWorldServer2.AdapterId=HelloWorldServer2
#iceboxregistry define end
其中:
MyIceGrid為registry裡定義的IceGrid.InstanceName屬性值,其後的ip port為 registry的ipport。
HelloWorldServer2.AdapterId=HelloWorldServer2格式為:{serviceName}.AdapterId={adapterName},本例serviceName和adapterName均為IceBox配置裡IceBox.Service.{serviceName}上的serviceName值。
5.1.3 Client傳送請求並獲得響應
修改3.5裡的獲取代理類的程式碼即可。完整程式碼如下:
package client;
import myice.demo.test.HelloWorldIDLPrx;
import myice.demo.test.HelloWorldIDLPrxHelper;
public class HelloWorldClient4IceGrid {
public static void main(String[] args) {
Ice.Communicator communicator = null;
try {
communicator = Ice.Util.initialize(new String[] {"--Ice.Default.Locator=MyIceGrid/Locator:tcp -h 192.168.1.7 -p 4061"});
Ice.ObjectPrx base = communicator.stringToProxy("helloWorldHandler2@HelloWorldServer2");
HelloWorldIDLPrx helloWorldClient = HelloWorldIDLPrxHelper.checkedCast(base);
if (helloWorldClient != null) {
String result = helloWorldClient.sayHello("fffkkk");
System.out.println(result);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (communicator != null) {
communicator.destroy();
}
}
}
}
5.1.4 執行
啟動IceBox服務,註冊HelloWorldServer2到Registry。
執行HelloWorldClient4IceGrid,呼叫遠端服務介面,控制檯列印如下:
Hello ZeroC ICE, [fffkkk]
成功呼叫遠端服務。
5.2 IceGrid Node
IceGrid Node為IceGrid叢集裡的節點,負責IceBox的裝載和啟停、採集主機的負載資訊和執行控制器IceGrid Admin的指令。
IceGrid Node是IceBox的容器,IceBox是服務(如HelloWorldServer2)的容器。一個IceGrid Node可以部署多個IceBox例項,這些例項可以是同一個IceBox的多個例項也可以是多個不同IceBox的例項組合。IceGrid Node連同其上執行的IceBox例項的資訊同步到了Registry中。
每個IceGrid Node都有唯一的名字,用來在IceGrid中標識其身份,可以在用一個伺服器上部署多個IceGrid Node,只要確保其都有唯一的名字即可。每個IceGrid Node都有一個配置檔案,定義了其啟動引數。
5.2.1 啟動IceGrid Node
Ø 配置檔案
編寫配置檔案:icegridnode.cfg
Ice.Default.Locator=MyIceGrid/Locator:tcp -h 192.168.1.7 -p 4061 # 指定Ice Registry資訊
IceGrid.Node.Name=node1
IceGrid.Node.Endpoints=tcp -h 192.168.1.7
IceGrid.Node.Data=D:\Program Files (x86)\ZeroC\data\node1 # 所有目錄需預先建立好
IceGrid.Node.Output=D:\Program Files (x86)\ZeroC\data\node1
Ice.StdErr=D:\Program Files (x86)\ZeroC\data\node1\stderr.log
Ice.StdOut=D:\Program Files (x86)\ZeroC\data\node1\stdout.log
Ø 啟動
進入ice安裝目錄下的bin子目錄,啟動registry,如:
D:\Program Files (x86)\ZeroC\Ice-3.6.3\bin>
icegridnode --Ice.Config=D:\ZerocICE\publish\rsrc\icegridnode.cfg
啟動後,可在IceGrid.Node.Data目錄下看到生成的一堆檔案。
5.3 IceGrid叢集
Ø 系統環境
CentOS 7,jdk1.8.0_91,zerocice 3.6.3
Ø 系統拓撲
伺服器 |
節點型別 |
服務 |
192.168.1.210 |
Ice Registry |
1個Ice Registry、1個IceBox |
192.168.1.212 |
IceGrid Node |
1個IceBox |
192.168.1.213 |
IceGrid Node |
1個IceBox |
Ø 伺服器安裝ice
CentOS下可安裝Red Hat版本ICE:
# cd /etc/yum.repos.d
# wget https://zeroc.com/download/rpm/zeroc-ice-el7.repo
# yum install ice-all-runtime ice-all-devel
5.3.1 icegridadmin使用
icegridadmin為IceGrid叢集管理工具,用於部署或升級IceGrid、檢視IceGrid節點狀態、啟停Node中的Server例項等。執行icegridadmin,需要先啟動Registry和Node。
Ø 啟動icegridadmin
進入ice安裝目錄下的bin子目錄,執行如下命令:
D:\Program Files (x86)\ZeroC\Ice-3.6.3\bin>
icegridadmin -u test -p test--Ice.Default.Locator="MyIceGrid/Locator:tcp -h 192.168.1.7 -p 4061"
即可進入icegridadmin操作符模式。由於Registry在本地且沒開啟許可權驗證,所以可用test/test使用者名稱及密碼來訪問 Registry登錄檔。
5.3.2 叢集搭建(暫單伺服器)
首先將程式包分發到各個伺服器上,根據配置檔案建立必要的目錄。
Ø IceBox程式碼
參照第3章和第4.1章節,完成IceBox伺服器程式碼的編寫。
此時不需要IceBox的配置檔案,將由IceGrid自動生成。
Ø 啟動Ice Registry
參考5.1.1章節,在192.168.2.10上啟動icegridregistry服務:
# icegridregistry --daemon--Ice.Config=/root/iceserver/rsrc/icegridregistry.cfg
啟動後可使用一下命令檢視啟動後執行在後臺的程式:
# ps aux | grep ice
配置檔案示例:
[root@nn rsrc]# more icegridregistry.cfg
IceGrid.InstanceName=MyIceGrid
IceGrid.Registry.Client.Endpoints=tcp -h 192.168.1.210 -p 4061
IceGrid.Registry.Server.Endpoints=tcp -h 192.168.1.210
IceGrid.Registry.Internal.Endpoints=tcp -h 192.168.1.210
IceGrid.Registry.Data=/root/iceserver/data/registry
IceGrid.Registry.PermissionsVerifier=MyIceGrid/NullPermissionsVerifier
IceGrid.Registry.AdminPermissionsVerifier=MyIceGrid/NullPermissionsVerifier
IceGrid.Registry.DynamicRegistration=1
Ø 啟動IceGrid Node
參考5.2.1章節,啟動icegridnode服務:
# icegridnode --daemon--Ice.Config=/root/iceserver/rsrc/icegridnode.cfg
各個服務的配置可根據需要做微調,如節點目錄。
配置檔案示例:
[root@nn rsrc]# more icegridnode.cfg
# 指定Ice Registry資訊
Ice.Default.Locator=MyIceGrid/Locator:tcp -h 192.168.1.210 -p 4061
IceGrid.Node.Name=node1
IceGrid.Node.Endpoints=tcp -h 192.168.1.210
IceGrid.Node.Data=/root/iceserver/data/node1
IceGrid.Node.Output=/root/iceserver/data/node1
Ice.StdErr=/root/iceserver/data/node1/stderr.log
Ice.StdOut=/root/iceserver/data/node1/stdout.log
Ø 啟動IceGrid叢集
編寫叢集配置檔案:
myicegrid.xml
<icegrid>
<application name="MyApplication">
<!-- IceBox等配置檔案裡的配置項 -->
<properties id="cfg_icebox">
<property name="IceBox.InheritProperties" value="1" />
<property name="Ice.PrintStackTraces" value="1"/>
<property name="Ice.Trace.Network" value="1" />
<property name="Ice.Trace.ThreadPool" value="1" />
<property name="Ice.Trace.Locator" value="1" />
</properties>
<!-- 負載均衡和服務容錯 -->
<replica-group id="rep_HelloWorldServer2Rep">
<!-- type: 負載均衡策略, n-replicas: 參與負載均衡的節點數,0應該表示自動獲取所有節點數 -->
<load-balancing type="round-robin" n-replicas="0"/>
<!-- 定義服務, identity: 新增到adapter裡時指定的ice object id, type: slice檔案定義的路徑(module名稱和interface名稱),或在ice生成的介面的抽象類中找到id -->
<object identity="helloWorldHandler2" type="::test::HelloWorldIDL" />
<object identity="helloIceHandler2" type="::test::HelloWorldIDL" />
</replica-group>
<server-template id="tpl_MyServer">
<!-- 定義模版裡的引數名稱 -->
<parameter name="id" />
<!-- 定義icebox容器, icebox節點可定義多個, id需要唯一; exe: 服務啟動命令, activation: 啟動方式 -->
<icebox id="MyServer-${id}" exe="java" activation="on-demand">
<!-- IceBox的配置檔案 -->
<properties>
<!-- 引用配置檔案 -->
<properties refid="cfg_icebox" />
</properties>
<!-- option: exe執行命令的引數 -->
<option>IceBox.Server</option>
<env>CLASSPATH=/usr/java/jdk1.8.0_91/lib/tools.jar;/root/iceserver/lib/*</env>
<!-- 服務定義,可定義多個service節點 -->
<service name="HelloWorldServer2" entry="icebox.HelloWorldServer2">
<adapter name="HelloWorldServer2" id="HelloWorldServer2-${id}" endpoints="tcp" replica-group="rep_HelloWorldServer2Rep" />
</service>
</icebox>
<!-- 直接定義服務 -->
<!-- <server id="MyServer-${id}" exe="" activation="on-demand">
<adapter name="Hello" endpoints="tcp" replica-group="ReplicatedHelloAdapter" />
</server> -->
</server-template>
<node name="node1">
<server-instance template="tpl_MyServer" id="1" />
</node>
<!-- <node name="node2">
<server-instance template="tpl_MyServer" id="2" />
</node> -->
</application>
</icegrid>
進入icegridadmin命令列:
# icegridadmin -u test -p test--Ice.Default.Locator="MyIceGrid/Locator:tcp -h 192.168.1.210 -p4061"
載入應用:
>>> application add/root/iceserver/rsrc/myicegrid.xml
更新/重新載入:
>>> application update/root/iceserver/rsrc/myicegrid.xml
啟動服務(啟動服務出錯,待解決):
>>> server start MyServer-1
常用命令:
server list 檢視啟動的伺服器
service list MyServer-1 檢視MyServer-1上的服務
service describe MyServer-1HelloWorldServer2 檢視MyServer-1下HelloWorldServer2服務的描述
adapter list 檢視所有Adapter
node list 檢視所有node
6 常見問題
相關文章
- 《ZeroC Ice權威指南》
- ZeroC釋出中文版Ice手冊
- 飛冰 - ICE Design Pro 使用指南
- 飛冰(ICE)4 月新動態
- zeroc ice 客戶端與服務端通訊例子(c++)客戶端服務端C++
- ZeroC ICE的遠端呼叫框架 Slice如何幫助我們進行Ice非同步程式設計(AMI,AMD)框架非同步程式設計
- Oracle基礎之function使用OracleFunction
- Swift之SQLite的基礎使用SwiftSQLite
- Oracle之procedure的基礎使用Oracle
- Ice中Monitor的使用
- Golang 基礎之函式使用 (三)Golang函式
- Golang 基礎之函式使用 (二)Golang函式
- Golang 基礎之函式使用 (一)Golang函式
- 前端基礎之jQuery基礎前端jQuery
- 冰與火之軟體
- 03 . Vue基礎之計算屬性,元件基礎定義和使用Vue元件
- 【Vim】基礎之基礎——指尖的舞蹈
- Javascript基礎之-thisJavaScript
- 類之基礎
- C#基礎之checked與 unchecked的使用C#
- 持續整合工具之Jenkins基礎使用Jenkins
- Linux基礎之使用者和組Linux
- TypeScript In ICETypeScript
- Golang 基礎之基礎語法梳理 (三)Golang
- 【0基礎學爬蟲】爬蟲基礎之自動化工具 Pyppeteer 的使用爬蟲
- 【0基礎學爬蟲】爬蟲基礎之網路請求庫的使用爬蟲
- 訊息型中介軟體之RabbitMQ基礎使用MQ
- 分散式監控系統之Zabbix基礎使用分散式
- WEB基礎之:CSS 使用者介面樣式WebCSS
- 測試基礎(四)Jmeter基礎使用JMeter
- drf之框架基礎框架
- Dart基礎之IsolateDart
- [java基礎]之常量Java
- Javascript基礎之-PromiseJavaScriptPromise
- java基礎之XMLJavaXML
- mongoose基礎使用Go
- webpack 基礎使用Web
- Markdown基礎使用