1. 程式人生 > 其它 >Qt+MPlayer音樂播放器開發筆記(一):ubuntu上編譯MPlayer以及Demo演示

Qt+MPlayer音樂播放器開發筆記(一):ubuntu上編譯MPlayer以及Demo演示

前言

正文

  • RabbitMQ是一個訊息中介軟體,相當於一箇中轉站;用於接收、儲存、轉發訊息資料

  • RabbitMQ的作用:

    1. 流量消峰:當伺服器處理不了過多的請求時,在進入伺服器之前先進入MQ,MQ會對請求做排序,防止伺服器宕機
    2. 應用解耦:當系統的某個子系統出現故障無法正常工作時,該子系統要處理的記憶體會被快取到訊息佇列中,當該子系統正常後再繼續處理;提高使用者體驗,避免使用者再次請求
    3. 非同步處理:有些服務間的呼叫是非同步的,當某個服務在工作時,其他服務不能呼叫該服務,可使用訊息佇列來進行監聽管理呼叫
  • MQ的核心:

    1. 生產者:產生資料傳送訊息的模組
    2. 交換機:用於接收生產者的訊息、將訊息推送到佇列中、處理訊息
    3. 佇列:相當於訊息快取區
    4. 消費者:用於接收訊息的模組
    5. 一個應用程式既可以是生產者,又可以是消費者;比如一個通訊工具,既可以傳送資訊,也可以接收資訊
  • 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

  • 訊息傳遞入門案例:

    1. 匯入所需依賴,新建一個類作為訊息生產者,定義一個佇列,建立連線工廠,建立連線,生成佇列,傳送訊息
    2. 執行後發現massage傳送到了rabbitmq,可在rabbitmq中檢視
    3. 新建一個類作為訊息消費者,建立連線工廠,建立連線,接收rabbitmq中的訊息,可指定回撥方法用於處理成功和失敗的情況
  • 工作佇列是為了避免立即執行大量任務,生產者傳送大量訊息到rabbitmq的佇列,佇列將訊息快取、排序、分發到不同的消費者

  • 輪訓分發訊息案例:

    1. 抽取連線的步驟抽取到一個工具類,新建生產者類和消費者類,消費者類啟動多個執行緒
    2. 當生產者傳送訊息時,訊息被多個執行緒(消費者類)平均接收
  • 訊息應答:消費者接收訊息並處理完成後,會告訴rabbitmq,這時rabbitmq會把訊息刪除了

  • 自動應答:建議不要使用,若消費者不能即使處理訊息,會導致訊息丟失

  • 手動應答:自定義應答方法

Channel.basicAck:用於肯定確認,RabbitMQ 已知道該訊息並且成功的處理訊息,可以將其丟棄了 
Channel.basicNack:用於否定確認
Channel.basicReject:用於否定確認,與 Channel.basicNack 相比少一個引數Multiple
	Multiple為true表示批量應答,即消費者同時處理多個訊息,其中一個訊息處理完成後,則告訴rabbitmq全處理完了
	Multiple為false表示不批量應答,即消費者同時處理多個訊息,其中一個訊息處理完成後,則告訴rabbitmq處理完的那個訊息

  • 訊息自動重新入隊,訊息會儲存在rabbitmq中,直到被消費者處理後、應答後才會刪除,當消費者出現異常或者宕機時導致處理失敗,rabbitmq會將訊息分發給另一個消費者處理

  • 手動應答 + 自動重新入隊案例:

    1. 新建一個類作為訊息生產者
    2. 新建一個類作為訊息消費者:讓該執行緒睡眠1秒後打印出接收到訊息,再新建一個訊息消費者類:讓該執行緒睡眠30秒後打印出接收的訊息,是為了模擬處理複雜的訊息;在兩個消費者類中設定為手動應答
    3. 測試:生產者傳送訊息,兩個消費者輪訓接收訊息,當第二個消費者在接收訊息時突然關閉服務,這時訊息沒處理完,又被自動分配到第一個消費者處理
  • 佇列持久化:
    在生產者類中設定
    訊息應答機制確保了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();
        }
    }
}