国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁(yè) > news >正文

創(chuàng)業(yè)初期要建立公司的網(wǎng)站嗎鄭州百度關(guān)鍵詞seo

創(chuàng)業(yè)初期要建立公司的網(wǎng)站嗎,鄭州百度關(guān)鍵詞seo,東莞企業(yè)網(wǎng)站找誰(shuí),潮州seo1.管道 2.信號(hào)量 2.1 概念 信號(hào)量 是一個(gè)計(jì)數(shù)器,用于實(shí)現(xiàn)進(jìn)程間互斥和同步。 信號(hào)量的取值可以是任何自然數(shù)。 最簡(jiǎn)單的信號(hào)量是只能取 0 和 1 的變量,這也是信號(hào)量最常見(jiàn)的一種形式,叫做二進(jìn)制信號(hào)量(Binary Semaphore&#…

1.管道

2.信號(hào)量

2.1 概念

信號(hào)量 是一個(gè)計(jì)數(shù)器,用于實(shí)現(xiàn)進(jìn)程間互斥和同步

信號(hào)量的取值可以是任何自然數(shù)。
最簡(jiǎn)單的信號(hào)量是只能取 0 和 1 的變量,這也是信號(hào)量最常見(jiàn)的一種形式,叫做二進(jìn)制信號(hào)量(Binary Semaphore)。
而可以取多個(gè)正整數(shù)的信號(hào)量被稱(chēng)為通用信號(hào)量。

2.2 特點(diǎn)

1.	信號(hào)量用于進(jìn)程間同步,若要在進(jìn)程間傳遞數(shù)據(jù)需要結(jié)合共享內(nèi)存。2.	信號(hào)量基于操作系統(tǒng)的 PV 操作,程序?qū)π盘?hào)量的操作都是 原子操作。3.	每次對(duì)信號(hào)量的 PV 操作不僅限于對(duì)信號(hào)量值加 1 或減 1,而且可以加減任意正整數(shù)。4.	支持信號(hào)量組。

2.3 原型

2.3.1 semget 創(chuàng)建或獲取一個(gè)信號(hào)量集函數(shù)

#include <sys/sem.h>// 創(chuàng)建或獲取一個(gè)信號(hào)量集 若成功返回信號(hào)量集ID,失敗返回-1
int semget(key_t key, int num_sems, int sem_flags);key:一個(gè)鍵值,用來(lái)標(biāo)識(shí)一個(gè)全局唯一的信號(hào)量集。要通過(guò)信號(hào)量通信的進(jìn)程使用相同的 key 來(lái)創(chuàng)建或獲取該信號(hào)量num_sems:指定要 創(chuàng)建/獲取信號(hào)量集中信號(hào)量的數(shù)目。創(chuàng)建:該值必須被指定。獲取:可以設(shè)置為 0.sem_flags:指定一組標(biāo)志。它低端 9 個(gè)比特是信號(hào)量的權(quán)限,其格式和含義都與系統(tǒng)調(diào)用的 open、model參數(shù)相同。此外,它還可以和 IPC_CREAT 標(biāo)志做按位 “或”運(yùn)算以創(chuàng)建新的信號(hào)量集。確保創(chuàng)建一組新的、唯一的信號(hào)量集:聯(lián)合使用 IPC_CREAT 和 IPC_EXCL.此時(shí),若創(chuàng)建的信號(hào)量集已存在,則 semget 返回錯(cuò)誤 并設(shè)置 errno 為 EEXIST.返回:成功:返回正整數(shù)值,是信號(hào)量級(jí)的標(biāo)識(shí)符失敗:-1,并設(shè)置 errno擴(kuò)展:若 semget 用于創(chuàng)建信號(hào)量集,則與之關(guān)聯(lián)的內(nèi)核數(shù)據(jù)結(jié)構(gòu)體 semid_ds	將被創(chuàng)建并初始化。semid_ds結(jié)構(gòu)體定義如下:#include <sys/sem,h>	//此結(jié)構(gòu)體用于描述 IPC 對(duì)象(信號(hào)量、共享內(nèi)存和消息隊(duì)列)的權(quán)限struct ipc_perm{key_t key;		//鍵值uid_t uid;		//所有者的有效用戶(hù) IDgid_t gid;		//所有者的有效組 IDuid_t cuid;		//創(chuàng)建者的有效用戶(hù) IDgid_t cgid;		//創(chuàng)建者的有效組 IDmode_t mode;	//訪問(wèn)權(quán)限...				//省略其他字段}struct semid_ds{struct ipc_perm sem_perm;		//信號(hào)量的操作權(quán)限unsigned long int sem_nsems;	//該信號(hào)量集中的信號(hào)量數(shù)目time_t sem_otime;				//最后一次調(diào)用 semop 的時(shí)間time_t sem_ctime;				//最后一次調(diào)用 semctl 的時(shí)間...								//省略其他填充字段}semget 對(duì) semid_ds 結(jié)構(gòu)體初始化包括:sem_perm.cuid 和 sem_perm.uid 設(shè)置為調(diào)用進(jìn)程的有效用戶(hù) IDsem_perm.cgid 和 sem_perm.gid 設(shè)置為調(diào)用進(jìn)程的有效組 IDsem_perm.mode 的最低 9 位設(shè)置為 sem_flags 參數(shù)的最低 9 位sem_nsems 設(shè)置為 num_semssem_otime 設(shè)置為 0sem_ctime 設(shè)置為當(dāng)前系統(tǒng)時(shí)間

2.3.1.1 semget 特殊參數(shù) IPC_PRIVATE

可以給 semget  函數(shù)傳一個(gè)特殊的鍵值 IPC_PRIVATE(其值為 0),這樣無(wú)論信號(hào)量是否已存在, semget 都將創(chuàng)建一個(gè)新的信號(hào)量。注意,不要因?yàn)檫@個(gè)名字就認(rèn)為這個(gè)創(chuàng)建的信號(hào)量就是私有的,
其他進(jìn)程,尤其是子進(jìn)程,也有方法來(lái)訪問(wèn)這個(gè)信號(hào)量。如下例,父、子進(jìn)程間使用一個(gè) IPC_PRIVATE 信號(hào)量來(lái)同步:
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <time.h>union semun
{int val;                  struct semid_ds* buf;     unsigned short int* array;struct seminfo* __buf;    
};// op=-1 執(zhí)行 P,op=1 執(zhí)行 V 
void pv( int sem_id, int op )
{struct sembuf sem_b;sem_b.sem_num = 0;sem_b.sem_op = op;sem_b.sem_flg = SEM_UNDO;semop( sem_id, &sem_b, 1 );
}int main( int argc, char* argv[] )
{int sem_id = semget( IPC_PRIVATE, 1, 0666 );    //創(chuàng)建一個(gè)信號(hào)量集 ,權(quán)限設(shè)置為 0666union semun sem_un;sem_un.val = 1;     semctl( sem_id, 0, SETVAL, sem_un );       //設(shè)置創(chuàng)建的信號(hào)量集 信號(hào)量 的值  為 1pid_t id = fork();if( id < 0 ){return 1;}else if( id == 0 ){time_t cur = time( NULL );printf( "child try to get binary sem: %s\n" ,ctime(&cur));//在父子進(jìn)程間共享 IPC_PRIVATE 信號(hào)量的關(guān)鍵在于二者都可以操作該信號(hào)量的標(biāo)識(shí)符 sem_idpv( sem_id, -1 );   //Vprintf( "child get the sem and would release it after 5 seconds\n" );sleep( 5 );pv( sem_id, 1 );    //Ptime_t cur1 = time( NULL );printf( "child try to get binary sem: %s\n" ,ctime(&cur1));exit( 0 );}else{time_t cur = time( NULL );printf( "parent try to get binary sem:%s\n" ,ctime(&cur));pv( sem_id, -1 );   //Vprintf( "parent get the sem and would release it after 5 seconds\n" );sleep( 5 );time_t cur1 = time( NULL );printf( "child try to get binary sem: %s\n" ,ctime(&cur1));pv( sem_id, 1 );    //P}waitpid( id, NULL, 0 );semctl( sem_id, 0, IPC_RMID, sem_un );  //立即移除信號(hào)量集return 0;
}

2.3.2 semop 對(duì)信號(hào)量集操作函數(shù)

與信號(hào)量關(guān)聯(lián)的一些重要內(nèi)核變量:
unsigned short semval;		//信號(hào)量的值
unsigned short semzcnt;		//等待信號(hào)量值變?yōu)?0 的進(jìn)程數(shù)量
unsigned short semncnt;		//等待信號(hào)量值增加的進(jìn)程數(shù)量
pid_t sempid;				//最后一次執(zhí)行 semop 操作的進(jìn)程 ID// 對(duì)信號(hào)量集進(jìn)行操作(就是改變上面的內(nèi)核變量),改變信號(hào)量的值,即執(zhí)行 P、V 操作,
#include <sys/sem.h>
int semop(int sem_id, struct sembuf * sem_ops, size_t num_sem_ops);sem_id:由 semget 調(diào)用返回的信號(hào)量集標(biāo)識(shí)符,用以指定被操作的目標(biāo)信號(hào)量集。
sem_ops:指向一個(gè) sembuf 結(jié)構(gòu)體類(lèi)型的數(shù)組,struct sembug{unsigned short int sem_num;short int sem_op;short int sem_flg;}		sem_num:信號(hào)量集中信號(hào)量的編號(hào),0表示信號(hào)量中第一個(gè)信號(hào)量。sem_op:指定操作類(lèi)型, 可選值為 正整數(shù)、0 和 負(fù)整數(shù)。每種類(lèi)型的操作行為受 參數(shù) sem_flg 影響。sem_flg:可選值: IPC_NOWAIT SEM_UNDO.含義:IPC_NOWAIT :無(wú)論信號(hào)量操作是否成功,semop 調(diào)用都將立即返回,類(lèi)似非阻塞 I/O。SEM_UNDO:當(dāng)進(jìn)程退出時(shí)取消正在進(jìn)行的 semop 操作。sembuf 中參數(shù) sem_op 和 sem_flg 按如下方式影響 函數(shù) semop 的行為:1.	sem_op > 0:將內(nèi)核信號(hào)量的值在增加 sem_op,此操作要求調(diào)用進(jìn)程對(duì)被操作信號(hào)量集擁有寫(xiě)權(quán)限。若此時(shí)設(shè)置了 SEM_UNDO 標(biāo)志,則系統(tǒng)將更新進(jìn)程的 semadj 變量(用以跟蹤進(jìn)程對(duì)信號(hào)量的修改情況)2.	sem_op = 0:表示這是一個(gè)“等待0(wait-for-zero)” 操作,此操作要求調(diào)用進(jìn)程對(duì)被操作信號(hào)量集有 讀 權(quán)限。1.若此時(shí) 信號(hào)量值是 0:則調(diào)用立即成功返回。2.若此時(shí) 信號(hào)量值不是 0,則 semop 函數(shù) 失敗返回 或阻塞進(jìn)程以等待信號(hào)量變?yōu)?0.在這種情況下:若 sem_flg 設(shè)置了 IPC_NOWAIT , semop 函數(shù)立即返回一個(gè)錯(cuò)誤,并設(shè)置 errno 為 EAGAIN.若未設(shè)置 IPC_NOWAIT ,則 內(nèi)核信號(hào)量值 +1,進(jìn)程被投入睡眠直到下列 3 個(gè)條件之一 發(fā)生:1.信號(hào)量的值 semval 變?yōu)?0 ,此時(shí)系統(tǒng)將該信號(hào)量的 semzcnt 值 -12.被操作信號(hào)量所在信號(hào)量集被進(jìn)程移除, 此時(shí) semop 調(diào)用失敗返回,errno 設(shè)置為 EIDRM3.調(diào)用被信號(hào)中斷,此時(shí) semop 調(diào)用失敗返回, errno 被設(shè)置為 EINTR,同時(shí)系統(tǒng)將 內(nèi)核信號(hào)量 semzcnt 值 -13. sem_op < 0表示對(duì)信號(hào)量值進(jìn)行減操作。此操作要求調(diào)用進(jìn)程對(duì)被操作信號(hào)量集擁有寫(xiě)權(quán)限。1.若 內(nèi)核信號(hào)量的值 semval 大于或等于 sem_op 的絕對(duì)值,則 將 semval - |sem_op|  操作成功。此時(shí)若設(shè)置了 SEM_UNDO 標(biāo)志,則系統(tǒng)將更新進(jìn)程的 semadj 變量。2.若 內(nèi)核信號(hào)量的值 semval 小于 sem_op 的絕對(duì)值,則 semop 失敗返回或阻塞進(jìn)程以等待信號(hào)量可用。在這種情況下,若 IPC_NOWAIT 標(biāo)志被指定時(shí), sempop 立即返回一個(gè)錯(cuò)誤,并設(shè)置 errno 為 EAGAIN.若 IPC_NOWAIT 標(biāo)志未指定	, 則 內(nèi)核信號(hào)量 semncnt 值 +1,進(jìn)程被投入睡眠直到下列 3 個(gè)條件之一 發(fā)生:1. 信號(hào)量 semval 的值變得 >= sem_op的絕對(duì)值,此時(shí)系統(tǒng)將該信號(hào)量的 semncnt 值 -1,并將 semval 減去 sem_op 的絕對(duì)值。同時(shí),如果 SEM_UNDO 標(biāo)志被設(shè)置,則系統(tǒng)更新 semadj 變量。2.被操作信號(hào)量所在的信號(hào)量集被移除,此時(shí) semop 調(diào)用失敗返回, errno 被設(shè)置為 EIDRM3.調(diào)用被信號(hào)中斷,此時(shí) semop 調(diào)用失敗返回,errno 被設(shè)置為 EINTR,同時(shí)系統(tǒng)將該信號(hào)量的 semncnt 值 -1.num_sem_ops:指定要執(zhí)行的操作個(gè)數(shù),即 sem_ops 數(shù)組中元素個(gè)數(shù)。返回:成功:0失敗:-1及 errno。失敗時(shí),sem_ops 數(shù)組中指定所有操作都不執(zhí)行。擴(kuò)展:semop 函數(shù)對(duì)數(shù)組 sem_op 中每個(gè)成員按照數(shù)組順序依次執(zhí)行,且該過(guò)程是原子操作(不可中斷的一個(gè)或者一系列操作, 也就是不會(huì)被線程調(diào)度機(jī)制打斷的操作, 運(yùn)行期間不會(huì)有任何的上下文切換(context switch))。

2.3.3 semctl 對(duì)信號(hào)量集操作函數(shù)

#include <sys/sem.h>
// 控制信號(hào)量集的相關(guān)信息
int semctl(int semid, int sem_num, int command, ...);semid:由 semget 調(diào)用返回的信號(hào)量集標(biāo)識(shí)符,以指定被操作的信號(hào)量集。
sem_num:指定被操作的信號(hào)量在信號(hào)量集中的編號(hào)。
command:指定要執(zhí)行的命令,詳見(jiàn)下表 13-2有的命令需要第 4 個(gè)參數(shù)
...:這個(gè)參數(shù)配合 command 使用,由用戶(hù)自己定義,但 sys/sem.h 頭文件給出推薦格式如下:union semun{int val;				//用于 SETVAL 命令struct semid_ds * buf;	//用于 IPC_STAT 和 IPC_SET 命令unsigned short * array;	//用于 GETALL 和 SETALL 命令struct seminfo * __buf; //用于 IPC_INFO 命令};struct seminfo{int semmap;		//Linux 內(nèi)核沒(méi)有使用int semmni;		//系統(tǒng)最多可以擁有的信號(hào)量集數(shù)目int semmns;		//系統(tǒng)最多可以擁有的信號(hào)量數(shù)目int semmnu;		//Linux 內(nèi)核沒(méi)有使用int semmsl;		//一個(gè)信號(hào)量集 最多允許包含的信號(hào)量數(shù)目int semopm;		//semop 一次最多能執(zhí)行的 sem_op 操作數(shù)目int semume;		//Linux 內(nèi)核沒(méi)有使用int semusz;		//sem_undo 結(jié)構(gòu)體的大小int semvmx;		//最大允許的信號(hào)量值//最多允許的 UNDO 次數(shù)(帶 SEM_UNDO 標(biāo)志的 semop 操作的次數(shù))int semaem;		}返回:成功;返回值取決于 command 參數(shù)。失敗:-1 及 errno。		

在這里插入圖片描述

2.共享內(nèi)存

2.1 概念

共享內(nèi)存 是最高效的 IPC 機(jī)制,因?yàn)?不涉及進(jìn)程之間任何數(shù)據(jù)傳輸。
但需要輔助手段來(lái)同步進(jìn)程對(duì)共享內(nèi)存的訪問(wèn),否則會(huì)產(chǎn)生竟態(tài)條件。Linux 共享內(nèi)存包含 4 個(gè)系統(tǒng)調(diào)用:shmget、shmat、shmdt、shmctl。

2.2 shmget 系統(tǒng)調(diào)用

//創(chuàng)建一段新的共享內(nèi)存,或者獲取一段已經(jīng)存在的共享內(nèi)存#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
key:key 是一個(gè)鍵值,用來(lái)標(biāo)識(shí)一段全局唯一的共享內(nèi)存。
size:指定共享內(nèi)存大小。若是創(chuàng)建,則 size 必須被指定。若是獲取,則 size 可被設(shè)為 0.
shmflg:與信號(hào)量的 semget 系統(tǒng)調(diào)用的 sem_flags參數(shù)相同,但 這個(gè)再多兩個(gè)標(biāo)志:1.	SHM_HUGETLB系統(tǒng)將使用 “大頁(yè)面” 來(lái)為共享內(nèi)存分配空間2.	SHM_NORESERVE不為共享內(nèi)存保留交換分區(qū)(swap空間)。這樣,當(dāng)物理內(nèi)存不足時(shí),對(duì)該共享內(nèi)存執(zhí)行寫(xiě)操作將觸發(fā) SIGSEGV 信號(hào)。
返回:成功:正整數(shù)值,共享內(nèi)存標(biāo)識(shí)符。失敗:-1,errno擴(kuò)展:shmget 創(chuàng)建共享內(nèi)存時(shí),所有字節(jié)都被初始化為 0,與之關(guān)聯(lián)的內(nèi)核數(shù)據(jù)結(jié)構(gòu) shmid_ds 將被創(chuàng)建并初始化:struct shmid_ds{struct ipc_perm shm_perm;		//共享內(nèi)存的操作權(quán)限size_t shm_segsz;				//共享內(nèi)存大小,單位是字節(jié)__time_t shm_atime;				//對(duì)這段內(nèi)存最后一次調(diào)用 shmat 的時(shí)間__time_t shm_dtime;				//對(duì)這段內(nèi)存最后一次調(diào)用 shmdt 的時(shí)間__time_t shm_ctime;				//對(duì)這段內(nèi)存最后一次調(diào)用 shmct 的時(shí)間__pid_t shm_cpid;				//創(chuàng)建者 pid__pid_t shm_lpid;				//最后一次執(zhí)行 shmat 或 shmdt 操作的 進(jìn)程 pidshmatt_t shm_nattach;			//目前關(guān)聯(lián)到此共享內(nèi)存的進(jìn)程數(shù)量...								//省略一些字段}#include <sys/sem,h>	//此結(jié)構(gòu)體用于描述 IPC 對(duì)象(信號(hào)量、共享內(nèi)存和消息隊(duì)列)的權(quán)限struct ipc_perm{key_t key;		//鍵值uid_t uid;		//所有者的有效用戶(hù) IDgid_t gid;		//所有者的有效組 IDuid_t cuid;		//創(chuàng)建者的有效用戶(hù) IDgid_t cgid;		//創(chuàng)建者的有效組 IDmode_t mode;	//訪問(wèn)權(quán)限...				//省略其他字段}shmget 對(duì) shmid_ds 初始化包括:shm_perm.cuid 和 shm_perm.uid 設(shè)置為調(diào)用進(jìn)程的有效用戶(hù) IDshm_perm.cgid 和 shm_perm.gid 設(shè)置為調(diào)用進(jìn)程的有效組 IDshm_perm.mode 的最低 9 位設(shè)置為 sem_flags 參數(shù)的最低 9 位shm_segzs 設(shè)置為 sizeshm_lpid、shm_nattach、shm_atime、shm_dtime 設(shè)置為 0sem_ctime 設(shè)置為當(dāng)前系統(tǒng)時(shí)間

2.3 shmat 和 shmdt 系統(tǒng)調(diào)用

共享內(nèi)存創(chuàng)建完后,
1.不能立即訪問(wèn),而是首先將它關(guān)聯(lián)到進(jìn)程地址空間(shmat 實(shí)現(xiàn))
2.使用完后,必須將它從進(jìn)程地址空間中分離(shmdt 實(shí)現(xiàn))

#include <sys/shm.h>
void shmat(int shm_id, const void * shm_addr, int shmflg);
shm_id:創(chuàng)建的共享內(nèi)存標(biāo)識(shí)。
shm_addr:指定將共享內(nèi)存關(guān)聯(lián)到進(jìn)程的哪塊地址空間。最終效果受 參數(shù) shmflg 的可選標(biāo)志 SHM_RND 的影響??赡艿那闆r:1.	若 shm_addr 為 NULL,則被關(guān)聯(lián)的地址由操作系統(tǒng)選擇。推薦這樣做。2.	若 shm_addr 非空 且 SHM_RND 未設(shè)置,則共享內(nèi)存被關(guān)聯(lián)到 addr 指定地址處。3.	若 shm_addr 非空 且 設(shè)置了 SHM_RND ,則被關(guān)聯(lián)的地址是 [shm_addr -(shm_addr % SHMLBA)]。SHMLBA 含義是“段低端邊界地址倍數(shù)”(Segment Low Boundary Address Multiple),它必須是內(nèi)存頁(yè)面大小(PAGE_SIZE)的整數(shù)倍。SHM_RND 的含義是圓整(round),即將共享內(nèi)存被關(guān)聯(lián)的地址向下圓整到離 shm_addr 最近的 SHMLBA 的整數(shù)倍地址處。
shmflg:可選標(biāo)志。如下:SHM_RND :SHM_RDONLY:進(jìn)程僅能讀取共享內(nèi)存的內(nèi)容。若沒(méi)有指定此標(biāo)志,則進(jìn)程可以對(duì)共享內(nèi)存進(jìn)行讀寫(xiě)操作(這取需要?jiǎng)?chuàng)建共享內(nèi)存時(shí)指定其讀寫(xiě)權(quán)限)。SHM_REMAP:如果地址 shmaddr 已經(jīng)被關(guān)聯(lián)到一段共享內(nèi)存上,則重新關(guān)聯(lián)。SHM_EXEC:指定對(duì)共享內(nèi)存執(zhí)行權(quán)限。
返回:成功:返回共享內(nèi)存被關(guān)聯(lián)到的地址。同時(shí)將修改內(nèi)核數(shù)據(jù)結(jié)構(gòu) shmid_ds 部分字段,如下:shm_nattach 加 1.shm_lpid 設(shè)置為調(diào)用進(jìn)程的 PID。shm_atime 設(shè)置為當(dāng)前的時(shí)間。失敗:(void*)-1,errno//將 shm_addr 處的共享內(nèi)存從進(jìn)程分離。
int shmdt (const void * shm_addr);
返回:成功:0。成功將修改內(nèi)核 shmid_ds 部分字段:shm_attach 減 1。shm_lpid 設(shè)置為 調(diào)用進(jìn)程ID。shm_dtime 設(shè)置為當(dāng)前時(shí)間。失敗:-1,errno

2.4 shmctl 系統(tǒng)調(diào)用

//控制共享內(nèi)存某些屬性
#include <sys/shm.h>
int shmctl(int shm_id, int command ,struct shmid_ds * buf);
shm_id:共享內(nèi)存標(biāo)識(shí)符。
command:指定要執(zhí)行的命令。所有支持命令如下表 13-3。
bufL:	配合 command 使用,詳見(jiàn)表 13-3.
返回:成功:返回值取決于 command 命令,詳見(jiàn) 表 13-3.失敗:-1,errno。

在這里插入圖片描述

2.5 POSIX 的共享內(nèi)存方法

注意:使用如下 POSIX 共享內(nèi)存函數(shù),編譯時(shí)需要指定鏈接選項(xiàng) -lrt//創(chuàng)建或打開(kāi)一個(gè) POSIX 共享內(nèi)存對(duì)象
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
int shm_open(const char * name, int oflag, mode_t mode);
shm_open 的使用方法與 open 系統(tǒng)調(diào)用完全相同。
name:指定要?jiǎng)?chuàng)建/打開(kāi)的共享內(nèi)存對(duì)象。從可移植性考慮:此參數(shù)應(yīng)使用 “/somename”的格式:以 “/” 開(kāi)始,后接多個(gè)字符,且這些字符都不是 “/”;以 “\0” 結(jié)尾,長(zhǎng)度不超過(guò) NAME_MAX (通常是 255)。
oflag:指定創(chuàng)建方式。可以是下列標(biāo)志中 一個(gè) 或 多個(gè)的 按位或。O_RDONLY只讀方式打開(kāi)共享內(nèi)存對(duì)象。O_RDWR		以可讀、可寫(xiě)方式打開(kāi)共享內(nèi)存對(duì)象O_CREAT	若共享內(nèi)存不存在,則創(chuàng)建之。此時(shí) mode 參數(shù)低 9 位指定該共享內(nèi)存對(duì)象的訪問(wèn)權(quán)限。共享內(nèi)存被創(chuàng)建時(shí),初始長(zhǎng)度為 0.O_EXCL和 O_CREAT 一起使用。若由 name 指定的共享內(nèi)存對(duì)象已存在,則 shm_open 返回錯(cuò)誤,否則就創(chuàng)建一個(gè)新的共享內(nèi)存對(duì)象。O_TRUNC若共享內(nèi)存已存在,則把它截?cái)?#xff0c;使其長(zhǎng)度為 0。//刪除創(chuàng)建的共享內(nèi)存
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
int shm_unlink(const char * name);
name:將該參數(shù)指定的共享內(nèi)存對(duì)象標(biāo)記為等待刪除。當(dāng)使用該共享內(nèi)存對(duì)象的進(jìn)程都使用 ummap 將它從進(jìn)程分離后,系統(tǒng)將銷(xiāo)毀這個(gè)共享內(nèi)存對(duì)象所占據(jù)的資源。

2.6 共享內(nèi)存實(shí)例

/*注意點(diǎn):	
1.每個(gè)子進(jìn)程只會(huì)往自己所處理連接所對(duì)應(yīng)的那一部分讀緩存中寫(xiě)入數(shù)據(jù),所以使用共享內(nèi)存的目的是“共享讀”。
因此,每個(gè)子進(jìn)程在使用共享內(nèi)存時(shí)都無(wú)需加鎖,這樣符合“聊天室服務(wù)器”的應(yīng)用場(chǎng)景,同時(shí)提高性能。2.程序啟動(dòng)時(shí)給 users 分配了足夠的空間,使他可以存儲(chǔ)所有可能的客戶(hù)連接的相關(guān)數(shù)據(jù)。
同時(shí),sub_process 也分配了足夠的空間。
這是犧牲空間換時(shí)間的例子。
*///一個(gè)子進(jìn)程處理一個(gè)客戶(hù)連接
//所有客戶(hù) socket 連接的讀緩沖設(shè)計(jì)為一塊共享內(nèi)存
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>#define USER_LIMIT 5
#define BUFFER_SIZE 1024
#define FD_LIMIT 65535
#define MAX_EVENT_NUMBER 1024
#define PROCESS_LIMIT 65536//處理客戶(hù)連接必要的數(shù)據(jù)
struct client_data
{sockaddr_in address;        int connfd; pid_t pid;          //處理這個(gè)連接的子進(jìn)程 IDint pipefd[2];      //和父進(jìn)程通信用的管道
};static const char* shm_name = "/my_shm";
int sig_pipefd[2];
int epollfd;
int listenfd;
int shmfd;
char* share_mem = 0;
//客戶(hù)連接數(shù)組
client_data* users = 0;     
//子進(jìn)程和客戶(hù)連接的映射關(guān)系表,用進(jìn)程PID來(lái)索引這個(gè)數(shù)組即可獲得該進(jìn)程所處理的客戶(hù)連接的編號(hào)
int* sub_process = 0;//當(dāng)前客戶(hù)數(shù)量
int user_count = 0;
bool stop_child = false;int setnonblocking( int fd )
{int old_option = fcntl( fd, F_GETFL );int new_option = old_option | O_NONBLOCK;fcntl( fd, F_SETFL, new_option );return old_option;
}void addfd( int epollfd, int fd )
{epoll_event event;event.data.fd = fd;event.events = EPOLLIN | EPOLLET;epoll_ctl( epollfd, EPOLL_CTL_ADD, fd, &event );setnonblocking( fd );
}void sig_handler( int sig )
{int save_errno = errno;int msg = sig;send( sig_pipefd[1], ( char* )&msg, 1, 0 );errno = save_errno;
}void addsig( int sig, void(*handler)(int), bool restart = true )
{struct sigaction sa;memset( &sa, '\0', sizeof( sa ) );sa.sa_handler = handler;if( restart ){sa.sa_flags |= SA_RESTART;}sigfillset( &sa.sa_mask );assert( sigaction( sig, &sa, NULL ) != -1 );
}void del_resource()
{close( sig_pipefd[0] );close( sig_pipefd[1] );close( listenfd );close( epollfd );shm_unlink( shm_name );delete [] users;delete [] sub_process;
}//停止一個(gè)子進(jìn)程
void child_term_handler( int sig )
{stop_child = true;
}//子進(jìn)程運(yùn)行函數(shù),
//idx:子進(jìn)程處理客戶(hù)連接的編號(hào)
//users:保存所有客戶(hù)連接數(shù)據(jù)的數(shù)組
//share_mem:住處共享內(nèi)存地址
int run_child( int idx, client_data* users, char* share_mem )
{//子進(jìn)程用 epoll 監(jiān)聽(tīng)客戶(hù)連接 和 與父進(jìn)程通信的管道文件描述符epoll_event events[ MAX_EVENT_NUMBER ];int child_epollfd = epoll_create( 5 );assert( child_epollfd != -1 );int connfd = users[idx].connfd;addfd( child_epollfd, connfd );int pipefd = users[idx].pipefd[1];addfd( child_epollfd, pipefd );int ret;//子進(jìn)程設(shè)置自己的信號(hào)處理函數(shù)addsig( SIGTERM, child_term_handler, false );while( !stop_child ){int number = epoll_wait( child_epollfd, events, MAX_EVENT_NUMBER, -1 );if ( ( number < 0 ) && ( errno != EINTR ) ){printf( "epoll failure\n" );break;}for ( int i = 0; i < number; i++ ){int sockfd = events[i].data.fd;//客戶(hù)連接有數(shù)據(jù)到達(dá)if( ( sockfd == connfd ) && ( events[i].events & EPOLLIN ) ){memset( share_mem + idx*BUFFER_SIZE, '\0', BUFFER_SIZE );//讀取到對(duì)應(yīng)的讀緩存中,讀緩存是共享內(nèi)存的一段,它開(kāi)始于 idx*BUFFER_SIZE 處,長(zhǎng)度為 BUFFER_SIZE 字節(jié)。故每個(gè)客戶(hù)連接的讀緩存是共享的。ret = recv( connfd, share_mem + idx*BUFFER_SIZE, BUFFER_SIZE-1, 0 );if( ret < 0 ){if( errno != EAGAIN ){stop_child = true;}}else if( ret == 0 ){stop_child = true;}else{//成功讀取客戶(hù)數(shù)據(jù)后通知主進(jìn)程(通過(guò)管道)來(lái)處理send( pipefd, ( char* )&idx, sizeof( idx ), 0 );}}//主進(jìn)程通知本進(jìn)程(通過(guò)管道)將第client個(gè)客戶(hù)額數(shù)據(jù)發(fā)送到本進(jìn)程負(fù)責(zé)的客戶(hù)端else if( ( sockfd == pipefd ) && ( events[i].events & EPOLLIN ) ){int client = 0;//接收主進(jìn)程發(fā)送來(lái)的數(shù)據(jù),即有客戶(hù)數(shù)據(jù)到達(dá)的連接編號(hào)ret = recv( sockfd, ( char* )&client, sizeof( client ), 0 );if( ret < 0 ){if( errno != EAGAIN ){stop_child = true;}}else if( ret == 0 ){stop_child = true;}else{send( connfd, share_mem + client * BUFFER_SIZE, BUFFER_SIZE, 0 );}}else{continue;}}}close( connfd );close( pipefd );close( child_epollfd );return 0;
}int main( int argc, char* argv[] )
{if( argc <= 2 ){printf( "usage: %s ip_address port_number\n", basename( argv[0] ) );return 1;}const char* ip = argv[1];int port = atoi( argv[2] );int ret = 0;struct sockaddr_in address;bzero( &address, sizeof( address ) );address.sin_family = AF_INET;inet_pton( AF_INET, ip, &address.sin_addr );address.sin_port = htons( port );listenfd = socket( PF_INET, SOCK_STREAM, 0 );assert( listenfd >= 0 );ret = bind( listenfd, ( struct sockaddr* )&address, sizeof( address ) );assert( ret != -1 );ret = listen( listenfd, 5 );assert( ret != -1 );user_count = 0;users = new client_data [ USER_LIMIT+1 ];sub_process = new int [ PROCESS_LIMIT ];for( int i = 0; i < PROCESS_LIMIT; ++i ){sub_process[i] = -1;}epoll_event events[ MAX_EVENT_NUMBER ];epollfd = epoll_create( 5 );assert( epollfd != -1 );addfd( epollfd, listenfd );ret = socketpair( PF_UNIX, SOCK_STREAM, 0, sig_pipefd );assert( ret != -1 );setnonblocking( sig_pipefd[1] );addfd( epollfd, sig_pipefd[0] );addsig( SIGCHLD, sig_handler );addsig( SIGTERM, sig_handler );addsig( SIGINT, sig_handler );addsig( SIGPIPE, SIG_IGN );bool stop_server = false;bool terminate = false;//創(chuàng)建共享內(nèi)存,作為所有客戶(hù) socket 連接的讀緩存shmfd = shm_open( shm_name, O_CREAT | O_RDWR, 0666 );assert( shmfd != -1 );ret = ftruncate( shmfd, USER_LIMIT * BUFFER_SIZE ); assert( ret != -1 );share_mem = (char*)mmap( NULL, USER_LIMIT * BUFFER_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0 );assert( share_mem != MAP_FAILED );close( shmfd );while( !stop_server ){int number = epoll_wait( epollfd, events, MAX_EVENT_NUMBER, -1 );if ( ( number < 0 ) && ( errno != EINTR ) ){printf( "epoll failure\n" );break;}for ( int i = 0; i < number; i++ ){int sockfd = events[i].data.fd;if( sockfd == listenfd )        //新連接到來(lái){struct sockaddr_in client_address;socklen_t client_addrlength = sizeof( client_address );int connfd = accept( listenfd, ( struct sockaddr* )&client_address, &client_addrlength );if ( connfd < 0 ){printf( "errno is: %d\n", errno );continue;}if( user_count >= USER_LIMIT ){const char* info = "too many users\n";printf( "%s", info );send( connfd, info, strlen( info ), 0 );close( connfd );continue;}//保存新連接相關(guān)數(shù)據(jù)users[user_count].address = client_address;users[user_count].connfd = connfd;//創(chuàng)建與子進(jìn)程管道ret = socketpair( PF_UNIX, SOCK_STREAM, 0, users[user_count].pipefd );assert( ret != -1 );pid_t pid = fork();if( pid < 0 ){close( connfd );continue;}else if( pid == 0 ){close( epollfd );close( listenfd );close( users[user_count].pipefd[0] );close( sig_pipefd[0] );close( sig_pipefd[1] );run_child( user_count, users, share_mem );munmap( (void*)share_mem,  USER_LIMIT * BUFFER_SIZE );exit( 0 );}else{close( connfd );close( users[user_count].pipefd[1] );addfd( epollfd, users[user_count].pipefd[0] );users[user_count].pid = pid;//記錄新客戶(hù)連接在數(shù)組 users中的索引值,建立進(jìn)程pid 和該索引值間的映射sub_process[pid] = user_count;user_count++;}}//處理信號(hào)else if( ( sockfd == sig_pipefd[0] ) && ( events[i].events & EPOLLIN ) ){int sig;char signals[1024];ret = recv( sig_pipefd[0], signals, sizeof( signals ), 0 );if( ret == -1 ){continue;}else if( ret == 0 ){continue;}else{for( int i = 0; i < ret; ++i ){switch( signals[i] ){case SIGCHLD:   //子進(jìn)程退出,表示某個(gè)客戶(hù)端關(guān)閉了連接{pid_t pid;int stat;while ( ( pid = waitpid( -1, &stat, WNOHANG ) ) > 0 ){//子進(jìn)程pid取得被關(guān)閉連接編號(hào)int del_user = sub_process[pid];sub_process[pid] = -1;if( ( del_user < 0 ) || ( del_user > USER_LIMIT ) ){printf( "the deleted user was not change\n" );continue;}//清除關(guān)閉連接的相關(guān)數(shù)據(jù)epoll_ctl( epollfd, EPOLL_CTL_DEL, users[del_user].pipefd[0], 0 );close( users[del_user].pipefd[0] );users[del_user] = users[--user_count];sub_process[users[del_user].pid] = del_user;printf( "child %d exit, now we have %d users\n", del_user, user_count ); }if( terminate && user_count == 0 ){stop_server = true;}break;}case SIGTERM:case SIGINT:{   //結(jié)束服務(wù)器程序printf( "kill all the clild now\n" );//addsig( SIGTERM, SIG_IGN );//addsig( SIGINT, SIG_IGN );if( user_count == 0 ){stop_server = true;break;}for( int i = 0; i < user_count; ++i ){int pid = users[i].pid;kill( pid, SIGTERM );}terminate = true;break;}default:{break;}}}}}else if( events[i].events & EPOLLIN )       //某個(gè)子進(jìn)程向父進(jìn)程寫(xiě)了數(shù)據(jù){int child = 0;ret = recv( sockfd, ( char* )&child, sizeof( child ), 0 );      //讀取管道數(shù)據(jù),child 變量記錄哪個(gè)客戶(hù)連接有數(shù)據(jù)到達(dá)printf( "read data from child accross pipe\n" );if( ret == -1 ){continue;}else if( ret == 0 ){continue;}else{   //向除負(fù)責(zé)處理第 chold 個(gè)客戶(hù)連接的子進(jìn)程外的 其他子進(jìn)程發(fā)送消息,通知它們有客戶(hù)要寫(xiě)數(shù)據(jù)for( int j = 0; j < user_count; ++j ){if( users[j].pipefd[0] != sockfd ){printf( "send data to child accross pipe\n" );send( users[j].pipefd[0], ( char* )&child, sizeof( child ), 0 );}}}}}}del_resource();return 0;
}

3. 消息隊(duì)列

消息隊(duì)列在兩個(gè)進(jìn)程間傳遞 二進(jìn)制塊數(shù)據(jù) 的方式。

每個(gè)數(shù)據(jù)塊都有一個(gè)類(lèi)型,接收方可以根據(jù)類(lèi)型來(lái)有選擇的接收數(shù)據(jù)
而不像管道 和 命名管道那樣必須先進(jìn)先出的接收數(shù)據(jù)。

Linux消息隊(duì)列 API 定義在 sys/msg.h 	頭文件中,
包括 4 個(gè)系統(tǒng)調(diào)用:
msgget、msgsnd、msgrcv、msgctl。

3.1 msgget 系統(tǒng)調(diào)用

//創(chuàng)建一個(gè)消息隊(duì)列或者獲取一個(gè)消息隊(duì)列
#include <sys/msg.h>
int msgget (key_t key, int msgflg);
key:表用來(lái)標(biāo)識(shí)一個(gè)全局唯一的消息隊(duì)列。
msgflg:使用和含義與 semget 的參數(shù) sem_flags參數(shù)相同。指定一組標(biāo)志。它低端 9 個(gè)比特是信號(hào)量的權(quán)限,其格式和含義都與系統(tǒng)調(diào)用的 open、model參數(shù)相同。此外,它還可以和 IPC_CREAT 標(biāo)志做按位 “或”運(yùn)算以創(chuàng)建新的信號(hào)量集。確保創(chuàng)建一組新的、唯一的信號(hào)量集:聯(lián)合使用 IPC_CREAT 和 IPC_EXCL.此時(shí),若創(chuàng)建的信號(hào)量集已存在,則 semget 返回錯(cuò)誤 并設(shè)置 errno 為 EEXIST.返回:成功:返回正整數(shù)值,是消息隊(duì)列的標(biāo)識(shí)符失敗:-1,并設(shè)置 errno擴(kuò)展:若msgget用于創(chuàng)建消息隊(duì)列,則與之關(guān)聯(lián)的內(nèi)核數(shù)據(jù)結(jié)構(gòu) msqid_ds 將被創(chuàng)建并初始化:struct 	msqid_ds{struct ipc_perm msg_perm;	//消息隊(duì)列的操作權(quán)限time_t msg_stime;			//最后一次調(diào)用 msgsnd 的時(shí)間time_t msg_rtime;			//最后一次調(diào)用 msgrcv 的時(shí)間time_t msg_ctime;			//最后一次被修改的時(shí)間unsigned long __msg_cbytes;	//消息隊(duì)列中已有的字節(jié)數(shù)msqqnum_t msg_qnum;			//消息隊(duì)列中已有的消息數(shù)msglen_t msg_qbytes;		//消息隊(duì)列允許最大字節(jié)數(shù)pid_t msg_lspid;			//最后執(zhí)行 msgsnd 的進(jìn)程 PIDpid_t msg_lrpid;			//最后執(zhí)行 msgrcv 的進(jìn)程 PID}		

3.2 msgsnd 系統(tǒng)調(diào)用

//把一條消息添加到消息隊(duì)列
#include <sys/msg.h>
int msgsnd(int msqid, const void * msg_ptr, size_t msg_sz, int msgflg);
msqid:消息隊(duì)列標(biāo)識(shí)符。即 msgget 調(diào)用返回值。
msg_ptr:指向一個(gè)準(zhǔn)備發(fā)送的消息,必須被定義為如下類(lèi)型:struct msgbuf{long mtype;			//消息類(lèi)型,必須是一個(gè)正整數(shù)。char mtext[512];	//消息數(shù)據(jù),}
msg_sz:消息的數(shù)據(jù)部分(mtext)的長(zhǎng)度??梢詾?0,表示沒(méi)有消息數(shù)據(jù)。
msgflg:控制 msgsnd 的行為。支持 IPC_NOWAIT 標(biāo)志,即以非阻塞方式發(fā)送消息。此時(shí) msgsnd 將立即返回并設(shè)置 errno 為 EAGAIN.默認(rèn)情況下,發(fā)送消息時(shí)若消息隊(duì)列滿(mǎn)了,則 msgsnd 將阻塞。處于阻塞狀態(tài)的 msgsnd 調(diào)用可能被如下兩種情況所中斷:1.消息隊(duì)列被移除。此時(shí) msgsnd 將立即返回并設(shè)置 errno 為 EIDRM。2.程序接收到信號(hào)。此時(shí) msgsnd 將立即返回并設(shè)置 errno 為 EINTR。返回:成功:0.成功將修改內(nèi)核數(shù)據(jù) msqid_ds 的部分字段,如下:msg_qnum 加1msg_lspid 設(shè)置為調(diào)用進(jìn)程的 PIDmsg_stime 設(shè)置為當(dāng)前時(shí)間失敗:-1,errno

3.3 msgrcv 系統(tǒng)調(diào)用

//從消息隊(duì)列中獲取消息
#include <sys/msg.h>
int msgrcv(int msqid, void * msg_ptr,size_t msg_sz, long int msgtype, int msgflg);
msqid:消息隊(duì)列標(biāo)識(shí)符
msg_ptr:用于存儲(chǔ)接收的消息
msg_sz:消息數(shù)據(jù)部分長(zhǎng)度。
msgtype:指定消息類(lèi)型。msgtype = 0:	讀取消息隊(duì)列中第一個(gè)消息。msgtype > 0:	讀取消息隊(duì)列中第一個(gè)類(lèi)型為 msgtype 的消息(除非指定了標(biāo)志 MSG_EXCEPT)msgtype < 0:	讀取消息隊(duì)列中第一個(gè)類(lèi)型值比 msgtype 的絕對(duì)值小的消息。	
msgflg:控制 msgrcv 的行為,可以是如下標(biāo)志的按位或:IPC_NOWAIT:	如果消息隊(duì)列中沒(méi)有消息,則 msgrcv 立即返回并設(shè)置 errno 為 ENOMSG.MSG_EXCEPT:	若 msgtype > 0 ,則接收消息隊(duì)列中第一個(gè)非 msgtype 類(lèi)型的消息。MSG_NOERROR:如果消息數(shù)據(jù)部分長(zhǎng)度超過(guò) msg_sz ,就將它截?cái)?。返?#xff1a;成功:0.成功將修改 內(nèi)核數(shù)據(jù)結(jié)構(gòu) msqid_ds 中部分字段:msg_qnum 減 1.msg_lrqid 設(shè)置為調(diào)用進(jìn)程 pid。msg_rtime 設(shè)置為當(dāng)前時(shí)間。失敗 :-1,errno
擴(kuò)展:處于阻塞狀態(tài)的 msgrcv 可能被如下兩種異常中斷:1.消息隊(duì)列被移除。 此時(shí) msgrcv 將立即返回,并設(shè)置 errno 為 EIDRM.2.程序接收到信號(hào)。 此時(shí) msgrcv 將立即返回,并設(shè)置 errno 為 EINTR.

3.4 msgctl 系統(tǒng)調(diào)用

//控制消息隊(duì)列某些屬性
#include <sys/msg.h>
int msgctl(int msqid, int command, struct msqid_ds * buf);
msqid:共享內(nèi)存標(biāo)識(shí)符。
command:指定要執(zhí)行的命令。詳見(jiàn)下表 13-4。
返回:成功:取決于 command 參數(shù),詳見(jiàn)下表 13-4。失敗:-1,errno。		

在這里插入圖片描述

4. IPC 命令

在這里插入圖片描述

5.進(jìn)程間傳遞文件描述符

fork 后,父進(jìn)程中打開(kāi)的文件描述符在子進(jìn)程中仍然保持打開(kāi)。

傳遞文件描述符是要在接收進(jìn)程中創(chuàng)建一個(gè)新的文件描述符,并且該文件描述符和發(fā)送進(jìn)程中被傳遞的文件描述符指向內(nèi)核中相同文件表項(xiàng)

示例:

#include <sys/socket.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>static const int CONTROL_LEN = CMSG_LEN( sizeof(int) );/// @brief 發(fā)送文件描述符 
/// @param fd 傳遞信息的 unix 域 socket
/// @param fd_to_send 待發(fā)送額文件描述符
void send_fd( int fd, int fd_to_send )
{struct iovec iov[1];struct msghdr msg;      char buf[0];iov[0].iov_base = buf;iov[0].iov_len = 1;msg.msg_name    = NULL;     //消息的協(xié)議地址  協(xié)議地址和套接口信息//在非連接的UDP中,發(fā)送者要指定對(duì)方地址端口,接受方用于的到數(shù)據(jù)來(lái)源,如果不需要的話(huà)可以設(shè)置為NULL//(在TCP或者連接的UDP中,一般設(shè)置為NULL)msg.msg_namelen = 0;        ///*  地址的長(zhǎng)度  */msg.msg_iov     = iov;     /*  多io緩沖區(qū)的地址  */ msg.msg_iovlen = 1;        /*  緩沖區(qū)的個(gè)數(shù)  */ cmsghdr cm;cm.cmsg_len = CONTROL_LEN;  /*  包含該頭部的數(shù)據(jù)長(zhǎng)度  */ cm.cmsg_level = SOL_SOCKET; /*  具體的協(xié)議標(biāo)識(shí)  */ cm.cmsg_type = SCM_RIGHTS;  /*  協(xié)議中的類(lèi)型  */ *(int *)CMSG_DATA( &cm ) = fd_to_send;msg.msg_control = &cm;      //設(shè)置輔助數(shù)據(jù)msg.msg_controllen = CONTROL_LEN;  /*  輔助數(shù)據(jù)的長(zhǎng)度  */   sendmsg( fd, &msg, 0 );//只用于套接口,不能用于普通的I/O讀寫(xiě),參數(shù)sockfd則是指明要讀寫(xiě)的套接口
}/// @brief 接收文件描述符
/// @param fd  
/// @return 
int recv_fd( int fd )
{struct iovec iov[1];struct msghdr msg;char buf[0];iov[0].iov_base = buf;  //指定用戶(hù)空間緩存區(qū)地址iov[0].iov_len = 1;     //指定 緩沖區(qū)長(zhǎng)度為 1msg.msg_name    = NULL;msg.msg_namelen = 0;msg.msg_iov     = iov;msg.msg_iovlen = 1;cmsghdr cm;msg.msg_control = &cm;msg.msg_controllen = CONTROL_LEN;recvmsg( fd, &msg, 0 );int fd_to_read = *(int *)CMSG_DATA( &cm );return fd_to_read;
}int main()
{int pipefd[2];int fd_to_pass = 0;int ret = socketpair( PF_UNIX, SOCK_DGRAM, 0, pipefd ); //創(chuàng)建進(jìn)程通信文件描述符assert( ret != -1 );pid_t pid = fork();assert( pid >= 0 );if ( pid == 0 ){close( pipefd[0] );//子進(jìn)程關(guān)閉一端fd_to_pass = open( "test.txt", O_RDWR, 0666 );  //子進(jìn)程打開(kāi)文件描述符send_fd( pipefd[1], ( fd_to_pass > 0 ) ? fd_to_pass : 0 );//子進(jìn)程向本地socket一端寫(xiě)數(shù)據(jù),并攜帶待傳遞的文件描述符close( fd_to_pass );//子進(jìn)程關(guān)閉打開(kāi)的文件描述符exit( 0 );}close( pipefd[1] );//主進(jìn)程關(guān)閉寫(xiě)端(因?yàn)樽舆M(jìn)程往這個(gè)方向?qū)?#xff09;fd_to_pass = recv_fd( pipefd[0] );  //主進(jìn)程接收文件描述符char buf[1024];memset( buf, '\0', 1024 );read( fd_to_pass, buf, 1024 );  //主進(jìn)程讀取接收的文件描述符中的數(shù)據(jù)printf( "I got fd %d and data %s\n", fd_to_pass, buf );close( fd_to_pass );    //主進(jìn)程關(guān)閉 接收的文件描述符。
}
http://aloenet.com.cn/news/46063.html

相關(guān)文章:

  • 網(wǎng)站大屏輪播圖效果怎么做公眾號(hào)排名優(yōu)化軟件
  • 怎樣做永久網(wǎng)站二維碼北京seo公司有哪些
  • 網(wǎng)站做線上銷(xiāo)售蘇州百度關(guān)鍵詞優(yōu)化
  • wordpress兼職sem seo
  • 精品網(wǎng)站建設(shè)平臺(tái)如何自己免費(fèi)制作網(wǎng)站
  • 哈爾濱網(wǎng)站建設(shè)外包公司申請(qǐng)自媒體平臺(tái)注冊(cè)
  • 網(wǎng)站建設(shè)銷(xiāo)售問(wèn)答品牌營(yíng)銷(xiāo)是什么
  • ps 怎么做網(wǎng)站杭州網(wǎng)站定制
  • win7 iis創(chuàng)建網(wǎng)站網(wǎng)絡(luò)推廣營(yíng)銷(xiāo)網(wǎng)
  • 重慶網(wǎng)站建設(shè)吧營(yíng)銷(xiāo)型網(wǎng)站
  • 自己制作的網(wǎng)站怎么做分頁(yè)今日時(shí)事新聞
  • 寧波網(wǎng)站建設(shè)的企業(yè)太原今日頭條
  • 百度推廣做網(wǎng)站什么價(jià)位網(wǎng)站開(kāi)發(fā)流程的8個(gè)步驟
  • asp網(wǎng)站vps搬家2024年重大新聞簡(jiǎn)短
  • 武漢做網(wǎng)站找哪家好世界球隊(duì)最新排名榜
  • 杭州未來(lái)科技網(wǎng)站建設(shè)高端建站
  • 企業(yè)信用網(wǎng)查詢(xún)網(wǎng)站優(yōu)化推廣培訓(xùn)
  • 建甌網(wǎng)站制作百度網(wǎng)站怎么提升排名
  • 自己做產(chǎn)品品牌網(wǎng)站谷歌官網(wǎng)網(wǎng)址
  • 杭州富陽(yáng)區(qū)網(wǎng)站建設(shè)公司seo排名軟件有用嗎
  • 鄭州響應(yīng)式網(wǎng)站建設(shè)如何找外包的銷(xiāo)售團(tuán)隊(duì)
  • 網(wǎng)絡(luò)工作室頭像seo積分優(yōu)化
  • 用flash做的網(wǎng)站展示品牌策劃方案模板
  • 網(wǎng)站二級(jí)域名 權(quán)重 盧松松學(xué)seo網(wǎng)絡(luò)推廣
  • 國(guó)內(nèi)醫(yī)療美容網(wǎng)站建設(shè)培訓(xùn)機(jī)構(gòu)不退費(fèi)最有效方式
  • 電子書(shū)推送網(wǎng)站怎么做會(huì)計(jì)培訓(xùn)班
  • 政府采購(gòu)網(wǎng)站的建設(shè)情況bing收錄提交
  • 個(gè)人博客網(wǎng)站開(kāi)發(fā)的原因鄭州seo排名優(yōu)化公司
  • flash 做ppt的模板下載網(wǎng)站北京seo招聘信息
  • wordpress 命令插件東莞seo靠譜