Qt+MPlayer音樂播放器開發筆記(一):ubuntu上編譯MPlayer以及Demo演示
前言
- 最近學習了尚矽谷RabbitMQ視訊教程:https://www.bilibili.com/video/BV1cb4y1o7zz
- 受益匪淺,根據自己的理解做了下筆記,不正確的地方歡迎指正
正文
-
RabbitMQ是一個訊息中介軟體,相當於一箇中轉站;用於接收、儲存、轉發訊息資料
-
RabbitMQ的作用:
- 流量消峰:當伺服器處理不了過多的請求時,在進入伺服器之前先進入MQ,MQ會對請求做排序,防止伺服器宕機
- 應用解耦:當系統的某個子系統出現故障無法正常工作時,該子系統要處理的記憶體會被快取到訊息佇列中,當該子系統正常後再繼續處理;提高使用者體驗,避免使用者再次請求
- 非同步處理:有些服務間的呼叫是非同步的,當某個服務在工作時,其他服務不能呼叫該服務,可使用訊息佇列來進行監聽管理呼叫
-
MQ的核心:
- 生產者:產生資料傳送訊息的模組
- 交換機:用於接收生產者的訊息、將訊息推送到佇列中、處理訊息
- 佇列:相當於訊息快取區
- 消費者:用於接收訊息的模組
- 一個應用程式既可以是生產者,又可以是消費者;比如一個通訊工具,既可以傳送資訊,也可以接收資訊
-
CentOS安裝RabbitMQ:
vi /etc/yum.repos.d/rabbitmq_erlang.repo # 配置 centos8 Erlang的下載源 yum install erlang # 安裝Erlang # 下載rabbitmq的rpm,傳輸centos yum install socat # 安裝socat依賴 rpm -ivh rabbitmq-server-3.8.1-1.el8.noarch.rpm # 安裝rabbitmq rabbitmq-plugins enable rabbitmq_management # 安裝web外掛 vi /usr/lib/rabbitmq/lib/rabbitmq_server-3.8.1/ebin/rabbit.app # 設定可遠端訪問 firewall-cmd --add-port=15672/tcp --permanent # 開放埠 firewall-cmd --add-port=5672/tcp --permanent # 開放埠 firewall-cmd --reload # 使防火牆生效 rabbitmq-server -detached # 後臺啟動 http://ip:15672/ # 瀏覽器訪問rabbitmq頁面 sudo rabbitmq-server # 控制檯啟動
詳情檢視:https://www.jianshu.com/p/8aece9517533
RabbitMQ啟動時報錯:error: node with name "rabbit" already running on "bogon"
錯誤原因:後臺程序被佔用
解決方案:
ps -ef|grep rabbitmq # 檢視程序
kill <程序id> # 殺死程序
# 再次啟動
啟動時報錯:Warning: PID file not written; -detached was passed.
錯誤原因:警告資訊,不影響
- 建立賬號:
rabbitmqctl add_user <使用者名稱> <密碼> rabbitmqctl set_user_tags <使用者名稱> administrator # 為當前賬號設定超級管理員角色許可權 rabbitmqctl set_permissions -p "/" admin ".*" ".*" ".*" # 表示admin使用者在"/"這個主機中具有配置、讀、寫許可權 # 設定格式:set_permissions [-p <vhostpath>] <user> <conf> <write> <read> "/"表示主機路徑,也可自定義其他路徑 rabbitmqctl list_users # 檢視所有賬戶和對應的角色 # 此時可在window系統的瀏覽器中訪問Linux的rabbitmq,輸入建立的賬號 rabbitmqctl stop_app # 關閉 rabbitmqctl reset # 重啟 rabbitmqctl start_app # 啟動
- window10上RabbitMQ環境配置:
1. 安裝erlang,配置環境變數
i. ERLANG_HOME = 安裝路徑
ii. path中新增:%ERLANG_HOME%\bin
iii. cmd輸入erl檢視版本驗證是否安裝成功
2. 安裝RabbitMQ
i. 進入rabbitMQ安裝路徑的sbin資料夾,開啟cmd
ii. rabbitmq-plugins enable rabbitmq_management # 安裝視覺化外掛
iii. 瀏覽器輸入:http://localhost:15672/ # 訪問RabbitMQ頁面,使用者名稱、密碼為guest
3. RabbitMQ常用命令:
i. net start RabbitMQ # 啟動
ii. net stop RabbitMQ # 停止
iii. rabbitmqctl status # 檢視狀態
詳情檢視:https://blog.csdn.net/qq_39915083/article/details/107034747
-
訊息傳遞入門案例:
- 匯入所需依賴,新建一個類作為訊息生產者,定義一個佇列,建立連線工廠,建立連線,生成佇列,傳送訊息
- 執行後發現massage傳送到了rabbitmq,可在rabbitmq中檢視
- 新建一個類作為訊息消費者,建立連線工廠,建立連線,接收rabbitmq中的訊息,可指定回撥方法用於處理成功和失敗的情況
-
工作佇列是為了避免立即執行大量任務,生產者傳送大量訊息到rabbitmq的佇列,佇列將訊息快取、排序、分發到不同的消費者
-
輪訓分發訊息案例:
- 抽取連線的步驟抽取到一個工具類,新建生產者類和消費者類,消費者類啟動多個執行緒
- 當生產者傳送訊息時,訊息被多個執行緒(消費者類)平均接收
-
訊息應答:消費者接收訊息並處理完成後,會告訴rabbitmq,這時rabbitmq會把訊息刪除了
-
自動應答:建議不要使用,若消費者不能即使處理訊息,會導致訊息丟失
-
手動應答:自定義應答方法
Channel.basicAck:用於肯定確認,RabbitMQ 已知道該訊息並且成功的處理訊息,可以將其丟棄了
Channel.basicNack:用於否定確認
Channel.basicReject:用於否定確認,與 Channel.basicNack 相比少一個引數Multiple
Multiple為true表示批量應答,即消費者同時處理多個訊息,其中一個訊息處理完成後,則告訴rabbitmq全處理完了
Multiple為false表示不批量應答,即消費者同時處理多個訊息,其中一個訊息處理完成後,則告訴rabbitmq處理完的那個訊息
-
訊息自動重新入隊,訊息會儲存在rabbitmq中,直到被消費者處理後、應答後才會刪除,當消費者出現異常或者宕機時導致處理失敗,rabbitmq會將訊息分發給另一個消費者處理
-
手動應答 + 自動重新入隊案例:
- 新建一個類作為訊息生產者
- 新建一個類作為訊息消費者:讓該執行緒睡眠1秒後打印出接收到訊息,再新建一個訊息消費者類:讓該執行緒睡眠30秒後打印出接收的訊息,是為了模擬處理複雜的訊息;在兩個消費者類中設定為手動應答
- 測試:生產者傳送訊息,兩個消費者輪訓接收訊息,當第二個消費者在接收訊息時突然關閉服務,這時訊息沒處理完,又被自動分配到第一個消費者處理
-
佇列持久化:
在生產者類中設定
訊息應答機制確保了rabbitmq正常的情況下訊息不會丟失
佇列設定持久化後,rabbitmq即使宕機或重啟後,該佇列中的訊息依然存在於rabbitmq
若將一個未持久化的佇列設定成持久化後,重啟會報錯,這時由於該佇列已經在rabbitmq中存在,在rabbitmq頁面刪除該佇列,再重啟執行緒,
這時該佇列在rabbitmq顯示的持久化
在rabbitmq控制檯可檢視設定了佇列持久化的訊息帶有一個大寫的D -
訊息持久化:
rabbitmq中的佇列持久化了,傳送的訊息也需設定持久化,否則rabbitmq重啟後,佇列存在,佇列中的訊息丟失了
在生產者類中傳送訊息時新增:MessageProperties.PERSISTENT_TEXT_PLAIN -
不公平分發:
即處理速度快的消費者多分配訊息,確保消費者不會出現空閒狀態
在消費者類新增:channel.basicQos(1) # 預設為0表示輪訓,1表示不公平分發 -
預取值:
即指定消費者處理多少訊息
在消費者類新增:channel.basicQos(5) # 這就表示分發5條,表示該消費者類會一直堆著5條,當該消費者類處理了1條,只剩4條時,又會接收1條訊息
參考程式碼
// 連線rabbitmq工具類
public class RabbitMqUtils {
//得到一個連線的 channel
public static Channel getChannel() throws Exception{
//建立一個連線工廠
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("182.92.234.71"); // rabbitmq的ip和賬戶密碼
factory.setUsername("admin");
factory.setPassword("123");
Connection connection = factory.newConnection(); // 建立連線
Channel channel = connection.createChannel();
return channel; // 返回通道
}
}
// 生產者
public class Task02 {
private static final String TASK_QUEUE_NAME = "ack_queue"; // 建立佇列
public static void main(String[] argv) throws Exception {
try (Channel channel = RabbitMqUtils.getChannel()){ // 獲取連線rabbitmq
/**
* 生成一個佇列
* 1.佇列名稱
* 2.佇列持久化
* 3.該佇列是否只供一個消費者進行消費 是否進行共享 true 可以多個消費者消費
* 4.是否自動刪除 最後一個消費者端開連線以後 該佇列是否自動刪除 true 自動刪除
* 5.其他引數
*/
channel.queueDeclare(TASK_QUEUE_NAME, false, false, false, null);
Scanner sc = new Scanner(System.in);
System.out.println("請輸入資訊");
while (sc.hasNext()) {
String message = sc.nextLine(); // 從控制檯獲取訊息
/**
* 傳送一個訊息
* 1.傳送到那個交換機
* 2.路由的 key 是哪個
* 3.訊息持久化
* 4.傳送訊息的訊息體
*/
channel.basicPublish("", TASK_QUEUE_NAME, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes("UTF-8")); // 傳送訊息到rabbitmq
System.out.println("生產者發出訊息" + message);
}
}
}
}
// 消費者
public class Work03 {
private static final String ACK_QUEUE_NAME="ack_queue";
public static void main(String[] args) throws Exception{
Channel channel = RabbitMqUtils.getChannel();
System.out.println("C1 等待接收訊息處理時間較短");
//訊息消費的時候如何處理訊息
DeliverCallback deliverCallback=(consumerTag,delivery)->{
String message= new String(delivery.getBody());
SleepUtils.sleep(1);
System.out.println("接收到訊息:"+message);
/**
* 訊息應答的具體處理:
* 1.訊息標記 tag
* 2.是否批量應答未應答訊息
*/
channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
};
// 不公平分發
//channel.basicQos(1)
// 預取值
channel.basicQos(5)
//採用手動應答
boolean autoAck=false;
/**
* 1.佇列名稱
* 2.是否手動應答
* 3.接收成功的處理
* 4.接收訊息失敗的回撥
*/
channel.basicConsume(ACK_QUEUE_NAME,autoAck,deliverCallback,(consumerTag)->{
System.out.println(consumerTag+"消費者取消消費介面回撥邏輯");
});
}
}
// 模擬處理時間的睡眠工具類
public class SleepUtils {
public static void sleep(int second){
try {
Thread.sleep(1000*second);
} catch (InterruptedException _ignored){
Thread.currentThread().interrupt();
}
}
}