進程間通信(IPC)

来源:https://www.cnblogs.com/FlyingDoG--BoxPiG/archive/2022/09/25/16725644.html
-Advertisement-
Play Games

進程間通信(Interprocess Communication,IPC)是指兩個或者多個進程之間進行數據交換的過程 ==進程擁有獨立的記憶體空間== 類別 簡單進程間通信 命令行參數(向子進程傳遞和exec系列函數) 這裡可以這麼理解:在創建子進程的時候,命令行參數是共用的 可以通過fork 的返回 ...


進程間通信(Interprocess Communication,IPC)是指兩個或者多個進程之間進行數據交換的過程 進程擁有獨立的記憶體空間

類別

簡單進程間通信

  • 命令行參數(向子進程傳遞和exec系列函數)
    • 這裡可以這麼理解:在創建子進程的時候,命令行參數是共用的
    • 可以通過fork 的返回值,傳遞
  • 環境列表 (子進程繼承父進程的環境列表和exec系列函數)
  • 信號 (信號本身就是一個數據,不同的信號表示不同的數據,sigqueue還可以攜帶信號附加值)
  • 文件 (文件就不贅述,Linux下萬物皆文件)

傳統進程間通信

  • 管道

    • 這裡管道又可以細分為有名管道和無名管道
    • 有名管道
    # mkfifo fifo
    # echo 要寫入的數據 > fifo
    # cat fifo
    # 管道本身不存儲數據。可以當成水管來理解
    # 水桶(文件)才是存放數據的容器
    # 水管是負責運輸,並且一根水管不可能同時做到往水桶裡加水和取水 
    
    • 編程模型
    步驟 進程A 函數 進程B 步驟
    1 創建管道 mkfifo ----
    2 打開管道 open 打開管道 1
    3 讀寫管道 read/write 讀寫管道 2
    4 關閉管道 close 關閉管道 3
    5 刪除管道 unlink
    • 無名管道 只適用於父子進程之間的通信
#include <unistd.h>
int pipe(int pipefd[2]);
//成功返回0   失敗返回-1
pipefd[2]  作為輸出參數 
  • 編程步驟:

    • 通過輸出參數pipefd得到兩個文件描述符,其中 pipefd[0]用於讀,pipefd[1]用於寫
    • pipe函數在內核中創建管道文件,並打開兩次,一次讀,一次寫
    • 需要在fork之前調用pipe函數
    • 調用fork創建子進程
    • 父子進程只允許使用無名管道的一端(如果進程想讀,則必須關閉寫,如果想寫,則必須關閉讀)
    • 寫數據的進程關閉讀端(pipefd[0]),讀數據的進程關閉寫端(pipefd[1])
    • 父子進程傳輸數據
    • 父子進程分別關閉自己的文件描述符
  • 記憶體映射(mmap)

    • mmap/munmap底層不維護任何東西,只是返回一個首地址,所分配記憶體位於堆中
    • brk/sbrk底層維護一個白板紙地,記錄所分配記憶體的結尾位置,所分配記憶體位於堆中,底層調用mmap/munmap
    • malloc底層維護一個雙向鏈表和必要的控制信息,不可越界訪問,所分配記憶體位於堆中,底層調用brk/sbrk
    • 每個進程都有虛擬的記憶體空間,虛擬記憶體地址只是一個數字 ,並沒有和實際的物理記憶體將關聯
    • 所謂記憶體分配與釋放,其本質就是建立或者取消虛擬記憶體和物理記憶體之間的映射關係
  #include <sys/mman.h>
  //虛擬記憶體映射到物理記憶體或者文件
  void *mmap(
      void *addr,     //虛擬記憶體起始位置,如果為NULL則系統自動選定合適的虛擬記憶體,成功則返回 一般給NULL
      size_t length,  //映射長度,以位元組為單位,自動按照(4K)頁對齊
      int prot,       //映射許可權
      int flags,      //映射標誌
      int fd,         //文件描述符,如果映射到文件則需要指定  如果不是映射到文件(匿名映射)則給0即可
      off_t offset    //文件偏移量,自動按照頁(4k)對齊
  );
  /*
  成功返回映射區記憶體的起地址,失敗返回-1 (MAP_FAILED)
  prot  許可權取值:
  PROT_EXEC  -  映射區可執行
  PROT_READ  -  映射區可讀
  PROT_WRITE -  映射區可寫
  PROT_NONE  -  映射區不可訪問
      如果既需要讀,也需要寫,則  PROT_READ|PROT_WRITE
  flags  映射標誌:
  MAP_FIXED          - 若在addr記憶體地址上無法創建映射,則失敗(無此標誌系統會自動調整合適位置)
  MAP_SHARED         - 對映射區域的寫入操作直接寫入到文件中
  MAP_PRIVATE        - 對映射區的寫入操作只寫入到緩衝區中,不會真正寫入到文件
  MAP_ANONYMOUS      - 匿名映射  將虛擬記憶體映射到物理記憶體而非文件    忽略fd 和 offset參數
  MAP_DENYWRITE      - 拒絕其它對文件的寫入操作
  MAP_LOCKED         - 鎖定映射區域,保證其不被置換
      一定需要 MAP_SHARED 和 MAP_PRIVATE  二選一
  */
      
  //取消記憶體映射    
  int munmap(void *addr,size_t length);

XSI進程間通信

IPC標識

  • 內核為每個進程間通信維護一個結構體形式的IPC對象
  • 該IPC對象可通過一個非負整數的IPC標識來引用
  • 與 文件描述符不同,IPC標識在使用時會持續加1,當達到最大值時,向0迴轉
  • 非負整數,唯一標識一個進程間通信的IPC對象

IPC鍵值

  • IPC標識是IPC對象的內部名稱(編號)
  • 若多個進程需要在同一個IPC對象上會合(使用同一個進程間通信渠道),則必須通過鍵值作為其外部名稱來引用該IPC對象,IPC鍵值外部名稱
  • 無論何時,只要創建IPC對象,就必須指定個鍵值
  • 鍵值的數據類型在sys/types.h頭文件中被定義為key_t類型,其原始類型就是長整型

兩個進程如何在同一個IPC對象上匯合

  • 方式一: 伺服器進程以PIC_PRIVATE為鍵值創建一個新的IPC對象,並將該IPC對象的標識存放在某外(如文件中),客戶端進程就只可以去該文件中讀取
  • 方式二: 在一個公共頭文件中,定義一個兩個進程都認可的鍵值,伺服器進程用此鍵值創建IPC對象,客戶端進程用該鍵值獲取 IPC對象
  • 方式三: 兩個進程事先約定好一個路徑名和一個項目ID(0-255),通過路徑名和ID調用ftok函數,將二者轉換為一個唯一的鍵值
#include <sys/types.h>
#include <sys/ipc.h>

key_t ftok(const char *pathname,int pro_id);
pathname   -  一個真實存在的文件或者目錄的路徑名
pro_id     -  項目ID,低8位有效,其值域[0,255]
    
   成功返回鍵值,失敗返回-1
    
註意:起作用的是pathname參數所表示的路徑,而非pathname字元串本身

實現方式

  • 共用記憶體

    基本特點:
    • 兩個或者更多的進程,共用同一塊系統內核負責維護的記憶體區域,其地址空間通常被映射到堆棧之間
    • 無需複製信息(數據),最快的一種IPC機制
    • 需要考慮同步訪問的問題
    • 內核為每個共用記憶體,維護一個shmid_ds結構體形式的共用記憶體對象
    #include <sys/types.h>
    #include <sys/shm.h>
    
    //1.創建/獲取共用記憶體     內核維護
    int shmget(key_t key,size_t size,int shmflg);
    /*
    	A.以參數key作為鍵值創建共用記憶體,如果共用記憶體已經存在,則獲取該共用記憶體
    	B.size參數指定共用記憶體的大小(單位位元組),建議取4096的整數倍
    		若希望創建共用記憶體,則必須指定size參數
    		若只是獲取已有的共用記憶體,則size參數可以傳遞0
    	C.參數shmflg標識
    		0	-  獲取,如果共用記憶體不存在則獲取失敗
    		IPC_CREAT	- 創建,不存在則創建   存在則獲取(除非指定IPC_EXCL)
    						如果IPC_CREAT需要給定共用記憶體的許可權(mode)   IPC_CREAT|0644
    		IPC_EXCL	- 排斥,和IPC_CREAT按位域,如果共用記憶體已經存在則失敗
    	成功返回共用記憶體的標識,失敗返回-1
    */
    
    //2.載入共用記憶體   將進程中的虛擬記憶體地址映射到共用記憶體中
    void* shmat(int shmid,void *shmaddr,int shmflg);
    /*
    	A.將shmid(shmget的返回值)參數所標識的共用記憶體,映射到調用進程的地址空間
    	B.可以通過參數shmaddr(進程中的虛擬地址)人為指定映射地址,也可以將參數置為NULL,由系統自動選擇
    	C.參數shmflg標識:
    		0	- 以讀寫方式使用共用記憶體
    		SHM_RDONLY	- 以只讀方式使用共用記憶體
    		SHM_RND	- 只在shmaddr參數非NULL時才起作用,表示對shmaddr參數向下取記憶體頁的整數倍作為映射地址
    		
    	成功返回映射地址,失敗返回-1(0XFFFFFFF)
    	
    	如果載入成功,內核將該共用記憶體的載入計數加1(共用記憶體由內核維護,記錄有多少個進程載入了該共用記憶體)
    */
    //3.卸載共用記憶體
    int shmdt(const void *shmaddr);
    /*
    	將參數shmaddr所指向載入的共用記憶體映射從調用進程的取消映射
    	成功返回0,失敗返回-1
    	如果卸載成功,內核會將該共用記憶體的載入計數減1
    */
    
    //4.銷毀/控制共用記憶體
    int shmctl(int shmid,int cmd,struct shmid_ds* buf);
    /*
    	A.參數shmid是shmget的返回值    是對shmid所標識的共用記憶體進行刪除/獲取共用記憶體的信息
    	B.cmd取值
    		IPC_STAT  -  獲取共用記憶體的屬性,通過buf參數輸出
    		IPC_SET   -  設置共用記憶體的屬性,通過buf參數輸入,僅三個屬性可設置
    				shm_perm.uid     用戶ID
    				shm_perm.gid     組ID
    				shm_perm.mode    許可權
    		IPC_RMID  -  標記刪除共用記憶體
    				並非真正刪除共用記憶體,只是做一個刪除標記,禁止其被繼續載入,但已有載入依然保留。
    				只有當該共用記憶體的載入計數為0且使用IPC_RMID時才真正被刪除
    	成功返回0  失敗返回-1
    */
    
    
    struct shmid_ds{
    	struct ipc_perm   shm_perm;   //所有者及許可權 
        size_t            shm_segsz;  //共用記憶體大小(以位元組為單位)
        time_t 			  shm_atime;  //最後載入時間
        time_t			  shm_dtime;  //最後卸載時間
        time_t 			  shm_ctime;  //最後修改時間
        pid_t 		      shm_cpid;   //創建共用記憶體的進程ID
        pid_t             shm_lpid;   //最後載入、卸載進程的ID
        shmatt_t          shm_nattch; //當前載入計數
        ...
    };
    
    struct ipc_perm{
      	key_t		__key;   //鍵值
        uid_t		uid;     //有效屬主ID
        gid_t		gid;     //有效屬組ID
        uid_t		cuid;    //有效創建者ID
        gid_t		cgid;    //有效創建組ID
        unsigned short mode; //許可權
        unsigned short __seq;//序列號
    };
    
    
    #ipcs -m       #查看當前系統的共用記憶體
    #ipcrm -m shmid    #刪除指定的共用記憶體
    
  • 消息隊列

    基本特點
    • 消息隊列是由一個系統內核負責存儲和管理,並通過消息隊列標識引用的數據鏈表
    • 可以通過msgget函數創建一個新的消息隊列 ,或者獲取一個已經存在的消息隊列
    • 通過msgsnd函數向消息隊列的後端追加消息(需要把消息從用戶空間拷貝到內核空間)
    • 通過msgrcv函數從消息隊列的前端按要求提取消息(需要把消息從內核空間拷貝到用戶空間)
    • 消息隊列中的每個消息除了消息本身數據以外,還包含消息類型和數據長度
    • 內核為每個消息隊列 ,維護一個msqid_ds結構體形式的消息隊列對象
    #include <sys/msg.h>
    
    //msgget 創建或者獲取消息隊列 
    int msgget(key_t key,int msgflg);
    /*
    	A.該函數以參數key作為鍵值創建消息隊列,如果存在則獲取消息隊列
    	B.msgflg標識
    		0		- 獲取,不存在即失敗
    		IPC_CREAT	- 創建,不存在則創建,已存在則獲取,除非      創建時需要給定許可權 IPC|0644
    		IPC_EXCL	- 排斥,創建時如果已經存在則創建失敗
    	成功返回消息隊列標識,失敗返回-1
    */
    //msgsnd向消息隊列發送消息
    int msgsnd(int msgqid,const void *msgp,size_t msgsz,int msgflg);
    /*
    	A. msgqid 消息隊列的標識  msgget函數的返回值
    	B. msgp參數是一個指針,指針指向一塊記憶體,記憶體中包含消息類型和消息數據
    		記憶體中的前4/8個位元組必須是一個大於0的整數,代表消息類型,其後緊跟消息數據
    		消息數據的位元組長度用msgsz參數表示     註意:msgsz長度並不包含消息類型4/8個位元組
                +------------+--------------------+
        msgp--> |消息類型(>0) | 消息數據             |
                +------------+--------------------+
                |<-4/8Byte-> |<----msgsz--------->|
        
    	C.若內核中消息隊列緩衝區有足夠的空閑空間,則此函數會將消息拷入緩衝區並立即返回0,表示發送成功,否則此函數會阻塞,直到內核中的消息隊列緩衝區有足夠的空閑空間為止(比如有消息被接收)
    	D.若msgflg參數包含IPC_NOWAIT位,則當內核中的消息隊列沒有足夠空閑空間時,此函數不會阻塞,而是直接返回-1,且errno設置為EAGAIN
    	成功返回0  失敗返回-1
    */
    
    //msgrcv 從消息隊列中接收消息
    ssize_t msgrcv(int msgqid,void *msgp,size_t msgsz,long msgtype,int msgflg);
    /*
    	A.msgqid 消息隊列標識,msgget函數的返回值
    	B.msgp指針指向一個包含消息類型(4byte)和消息數據的記憶體塊,用於存儲消息類型和消息數據本身
    	C.msgsz參數用來標明消息數據緩衝區位元組大小   msgp指針指向的記憶體塊的大小-4/8byte
    	D.若所接收到的消息位元組數據大於msgsz參數,即消息太長
    	E.如果msgflg參數中包含MSG_NOERROR位,則消息太長會被截取msgsz位元組返回,剩餘部分會被丟棄
    		如果msgflg參數不包含MSG_NOERROR五個,消息太長時,不會對該消息做任何處理,直接返回-1,且errno設置為E2BIG 
    	F.msgtype參數表示期望接收哪類消息
    		msgtype = 0  - 返回消息隊列中的第一條消息
    		msgtype > 0  - 若msgflg參數不包含MSG_EXCEPT位,則返回消息隊列中第一個類型為msgtype的消息
    				   如果msgflg參數包含MSG_EXCEPT位,則返回消息隊列中第一個消息類型不為msgtype的消息
            msgtype < 0  - 返回消息隊列中類型小於等於msgtype絕對值的消息
            		   如果有多條消息滿足,則返回消息類型最小的第一條消息
        G.若消息隊列中有可接收的消息,則此函數會將該消息移出消息隊列拷貝到msgp記憶體中並立即返回0,表示接收成功
        	如果消息隊列中沒有可接收的消息,則此函數會阻塞,直到消息隊列中有可接收的消息為止
        H.如果msgflg參數包含IPC_NOWAIT位,則當消息隊列中沒有可接收的消息時(沒有滿足要求的消息),則此函數不會阻塞,而是返回-1,設置errno為ENOMSG
        成功返回所接收到消息數據的位元組數,失敗返回-1 
    
    */
    
    
    //msgctl銷毀/控制消息隊列
    int msgctl(int msgqid,int cmd,struct smqid_ds *buf);
    /*
    cmd的取值:
    	IPC_STAT	- 獲取消隊列的屬性,通過buf參數輸出
    	IPC_SET		- 設置消息隊列的屬性,通過buf輸入
    		msg_perm.uid
    		msg_perm.gid
    		msg_perm.mode
    		msg_qbytes
    	IPC_RMID	- 立即刪除消息隊列
    		此時所有阻塞在該消息隊列的,msgsnd/msgrcv函數調用都會立即返回失敗,errno設置為EIDRM
    	成功返回0   失敗返回-1
    */
    
    struct msqid_ds{
      	struct ipc_perm    msg_perm;    //許可權依賴
        time_t             msg_stime;   //最後發送時間
        time_t             msg_rtime;   //最後接收時間
        time_t             msg_ctime;   //最後修改時間
        unsigned long      _msg_cbytes; //消息隊列中的位元組數
        msgqumt_t          msg_qnum;    //消息隊列中消息數
        msglen_t           msg_qbytes;  //消息隊列能容納的最大位元組數
        pid_t              msg_lspid;   //最後發送消息進程ID
        pid_t              msg_lrpid;   //最後接收消息進程ID
    };
    
    struct ipc_perm{
      	key_t		__key;   //鍵值
        uid_t		uid;     //有效屬主ID
        gid_t		gid;     //有效屬組ID
        uid_t		cuid;    //有效創建者ID
        gid_t		cgid;    //有效創建組ID
        unsigned short mode; //許可權
        unsigned short __seq;//序列號
    };
    
    #ipcs -q   # 查看消息隊列
    #ipcrm -q msqid   # 刪除指定的消息隊列
    
  • 信號量

    基本特點
    • 本質上是用於限制對於共用資源訪問的進程數量 計數器
      • 計數器如果設置為1,表示任意時刻只允許一個進程對共用資源進行訪問 文件鎖寫鎖 獨占鎖
    • 多個進程獲取有限資源操作模式
        1. 獲取控制該資源的信號量
        2. 若信號量的值大於0,則進程可以使用該資源,為了表示該進程已獲得該資源,需要將信號量的值減1
        3. 若信號等於0,則該進程休眠等待資源,直到信號量的值大於0,進程被喚醒,執行1步驟
        4. 當進程不再使用該資源時,為了表示進程釋放該資源,需要將信號量的值加1,正在休眠等待該資源的其它進程將會被喚醒
    • 信號量 類似於 鎖
    #include <sys/sem.h>
    
    //semget  創建/獲取信號量集  信號量數組
    int semget(key_t key,int nsems,int semflg);
    /*
    	該函數是以key作為鍵值創建一個信號量集合(nsems參數表示集合中信號量的數量),如果是獲取已經存在的信號量集合則nsems可以取0
    	semflg取值:
    		0 		- 獲取,不存在則失敗
    		IPC_CREAT	- 創建,不存在則創建,存在即獲取,除非IPC_EXCL
    		IPC_EXCL	- 排斥,和IPC_CREAT一起使用,如果信號量集合存在則失敗
        成功返回信號量集合標識,失敗返回-1
    
    */
    //semop 操作信號量/信號量集合
    int semop(int semid,struct sembuf *sops,unsigned nsops);
    /*
    	semid參數是信號量集合的標識,semget函數的返回值
    	sops: 其實是一個數組的首地址   如果只有一個元素時,可以是一個元素的首地址
    	nsops:數組長度
    		sops數組中每個元素都是stuct sembuf的數據  執行操作如下:
    			若sem_op大於0,則將其加到sem_num下標所表示的信號量的計數值上,以表示對資源的釋放
    			若sem_op小於0,則將其從sem_num下標所表示的信號量減去sem_op的絕對值,以表示對資源的獲取
    			若sem_num信號量的計數值不夠減(信號量數值不能為負),則此函數會阻塞,直到該信號量夠減為止,以表示對資源的等待;
    			若sem_flg包含IPC_NOWAIT,則當sem_num信號量計數值不夠減時,此函數不會阻塞,而是返回-1,errno設置為EAGAIN,以便在等待資源的同時還可以做其它處理
    			若sem_op等於0,則直到sem_num所表示的信號量的計數值為0時才返回,除非sem_flg包含IPC_NOWAIT
    	成功返回0,失敗返回-1
    */
    
    struct sembuf{
      	unsigned short  sem_num;    //信號量下標    下標從0開始,表示操作哪一個信號量
        short           sem_op;     //操作數    1  -1
        short           sem_flg;    //操作標記
    };
    
    
    //semctl 銷毀/控制信號量集
    int semctl(int semid,int semnum,int cmd);
    int semctl(int semid,int semnum,int cmd,union semun arg);
    /*
    IPC_STAT- 獲取信號量集合的屬性,通過arg.buf輸出
    IPC_SET	- 設置信號量集合的屬性,通過arg.buf輸入
    		sem_perm.uid
    		sem_perm.gid
    		sem_perm.mode
    IPC_RMID- 立即刪除信號量集合
    		此時所有阻塞在對該信號量集合的semop函數調用,都會立即返回失敗,errno設置為EIDRM
    		
    GETALL	- 獲取信號量集合中每個信號量的計數值,通過arg.array輸出
    SETALL	- 設置信號量集合中每個信號量的計數值,通過arg.array輸入
    GETVAL	- 獲取信號量集合中,下標為semnum信號量的計數值,通過返回值輸出
    SETVAL	- 設置信號量集合中,下標為semnum信號量的計數值,通過arg.val輸入
    
    註意:只有針對信號量集合中具體某個信號量操作時,才會使用semnum參數,針對整個信號量集合操作,會忽略semnum
    成功因cmd而異,失敗返回-1
    
    
    */
    
    
    union emun{
    	int            val;     //value for SETVAL
    	struct sem_ds  *buf;    //Buffer for IPC_STAT  IPC_SET
    	unsigned short *array;  //Array for GETALL  SETALL
    	struct seminfo *__buf;  //buffer for IPC_INFO
    };
    
    struct sem_ds{
        struct ipc_perm     sem_perm;   //許可權
        time_t              sem_otime;  //最後semop操作的時間
        time_t              sem_ctime;  //最後修改時間
        unsigned short      sem_nsems;  //信號量集合中信號量的數據
    };
    
    struct ipc_perm{
      	key_t		__key;   //鍵值
        uid_t		uid;     //有效屬主ID
        gid_t		gid;     //有效屬組ID
        uid_t		cuid;    //有效創建者ID
        gid_t		cgid;    //有效創建組ID
        unsigned short mode; //許可權
        unsigned short __seq;//序列號
    };
    

網路進程間通信

本文來自博客園,作者:打工搬磚日記,轉載請註明原文鏈接:https://www.cnblogs.com/FlyingDoG--BoxPiG/p/16725644.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 開發環境 python 3.8: 解釋器 pycharm: 代碼編輯器 requests 發送請求 pyecharts 繪製圖表 pandas 讀取數據 爬蟲案例思路流程: 一. 數據來源分析: 確定需求, 採集那個網站上面什麼數據 抓包分析, 通過開發者工具進行抓包分析<瀏覽器自帶工具>開發 ...
  • 我國目前並未出台專門針對網路爬蟲技術的法律規範,但在司法實踐中,相關判決已屢見不鮮,K 哥特設了“K哥爬蟲普法”專欄,本欄目通過對真實案例的分析,旨在提高廣大爬蟲工程師的法律意識,知曉如何合法合規利用爬蟲技術,警鐘長鳴,做一個守法、護法、有原則的技術人員。 案情介紹 江蘇省無錫市梁溪區人民法院審結了 ...
  • python爬蟲爬取國家科技報告服務系統數據,共計30餘萬條 按學科分類【中圖分類】 共計三十餘萬條科技報告數據 爬取的網址:https://www.nstrs.cn/kjbg/navigation !!! 如果要完整地跑起來代碼,需要先看一下我的這篇博客,完成IP代理池的相關配置: https:/ ...
  • 介紹 基本 Yarp 示例顯示從 appsettings.json 載入的代理配置。相反,代理配置可以從您選擇的源以編程方式載入。您可以通過提供幾個實現 IProxyConfigProvider 和 IProxyConfig 的類來做到這一點。 可以使用配置過濾器在載入序列期間修改配置。 結構 IP ...
  • 在Linux系統中,也是存在目錄的概念的,但是Linux的目錄結構和Windows的目錄結構是存在比較多的差異的 在Windows目錄下,是一個一個的盤符(C盤、D盤、E盤),目錄是歸屬於某一個盤符的。主要記錄linux的配置和指令。 ...
  • 大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家分享的是MCUXpresso IDE下生成鏡像文件的方法及其與IAR,MDK差異。 痞子衡很久以前寫過一篇文章 《ARM Cortex-M鏡像文件(.bin/.hex/.s19)》,詳細介紹了三種流行的鏡像文件格式,這些鏡像文件不同於可執行文件 ...
  • 痞子衡嵌入式半月刊: 第 63 期 這裡分享嵌入式領域有用有趣的項目/工具以及一些熱點新聞,農曆年分二十四節氣,希望在每個交節之日準時發佈一期。 本期刊是開源項目(GitHub: JayHeng/pzh-mcu-bi-weekly),歡迎提交 issue,投稿或推薦你知道的嵌入式那些事兒。 上期回顧 ...
  • 前幾天裝了幾台linux伺服器,安裝操作系統的時候,選擇了預設磁碟分區,結果導致後面主目錄分區空間不夠用了,需要把其他分區的空間劃分給主分區一點。 下麵以CentOS6.5演示: 一、查看當前系統的磁碟分佈: df -h 發現root分區只有50G,home分區有864G。那麼我需要將850G的容量 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...