這兩天學習的東西有點多,感覺完全應付不過來了 ,一直在消化這幾天學習的東西所以2號、3號、4號的學習內容沒有及時總結,在此表示深深的愧疚,今天把這些天學習的知識點彙總一下。
主要學習了IPC進程間通信,IPC包括:
1、消息傳遞(管道、FIFO、消息隊列);
2、同步(互斥鎖,條件變量,讀寫鎖,文件與記錄鎖、信號燈);
3、共享內存;
4、遠程過程調用(Solaris 門,Sun RPC)。
總結IPC前先複習一下多進程:
一、進程創建:
1、system函數
通過調用shell程序/bin/sh –c來執行string所指定的命令,該函數在內部是通過調用execve(“/bin/sh”,..)函數來實現的。通過system創建子進程後,原進程和子進程各自運行,相互間關聯較少。如果system調用成功,將返回0。
2、fork函數
在linux中fork函數時非常重要的函數,它從已存在進程中創建一個新進程。新進程爲子進程,而原進程爲父進程。它和其他函數的區別在於:它執行一次返回兩個值。其中父進程的返回值是子進程的進程號,而子進程的返回值爲0.若出錯則返回-1.因此可以通過返回值來判斷是父進程還是子進程。
fork函數創建子進程的過程爲:使用fork函數得到的子進程是父進程的一個複製品,它從父進程繼承了進程的地址空間,包括進程上下文、進程堆棧、內存信息、打開的文件描述符、信號控制設定、進程優先級、進程組號、當前工作目錄、根目錄、資源限制、控制終端,而子進程所獨有的只有它的進程號、資源使用和計時器等。通過這種複製方式創建出子進程後,原有進程和子進程都從函數fork返回,各自繼續往下運行,但是原進程的fork返回值與子進程的fork返回值不同,在原進程中,fork返回子進程的pid,而在子進程中,fork返回0,如果fork返回負值,表示創建子進程失敗。(vfork函數)
3、exec函數族
exec*由一組函數組成
int execl(const char *path, const char *arg, ...)
exec函數族的工作過程與fork完全不同,fork是在複製一份原進程,而exec函數是用exec的第一個參數指定的程序覆蓋現有進程空間(也就是說執行exec族函數之後,它後面的所有代碼不在執行)。
path是包括執行文件名的全路徑名
arg是可執行文件的命令行參數,多個用,分割注意最後一個參數必須爲NULL。
二、共享內存與信號量
共享內存機制主要用到 shmget shmat shmdt shmctl 函數;
原理及實現:system V IPC機制下的共享內存本質是一段特殊的內存區域,進程間需要共享的數據被放在該共享內存區域中,所有需要訪問該共享區域的進程都要把該共享區域映射到本進程的地址空間中去。這樣一個使用共享內存的進程可以將信息寫入該空間,而另一個使用共享內存的進程又可以通過簡單的內存讀操作獲取剛纔寫入的信息,使得兩個不同進程之間進行了一次信息交換,從而實現進程間的通信。共享內存允許一個或多個進程通過同時出現在它們的虛擬地址空間的內存進行通信,而這塊虛擬內存的頁面被每個共享進程的頁表條目所引用,同時並不需要在所有進程的虛擬內存都有相同的地址。進程對象對於共享內存的訪問通過key(鍵)來控制,同時通過key進行訪問權限的檢查。
shmget 通過關鍵字建立共享內存;
shmat 返回共享內存地址
shmdt 斷開與共享內存的鏈接
Shmctl 回收共享內存
三、IPC進程通信的應用:select多進程服務器
頭文件:
#ifndef __CLINET_H__
#define __CLINET_H__
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/sem.h>
typedef struct tag
{
int m_flag ;
char m_buf[1024] ;
}MBUF, *pMBUF;
void P(int semid) ;
void V(int semid);
#endif
客戶端輸入端:
/*************************************************************************
> File Name: client_in.c
> Author: Comst
> Mail:[email protected]
> Created Time: Wed 04 Feb 2015 03:04:39 PM CST
************************************************************************/
#include "client.h"
#include<sys/stat.h>
#include<sys/types.h>
#include<sys/fcntl.h>
#define PATH "/home/comst/pipe"
#define SERVER "server.fifo"
int main(int argc, char* argv[])//shm_key sem_key
{
char server_name[128]= "" ;
char read_file[128], write_file[128] ;
char msg[32] ="" ;
int fd_r, fd_w ;
sprintf(server_name, "%s/%s", PATH, SERVER);
int fd_server = open(server_name, O_WRONLY);
memset(read_file, 0, 128);
memset(write_file, 0, 128);
sprintf(read_file, "%s/%d_r.fifo", PATH, getpid());
sprintf(write_file, "%s/%d_w.fifo", PATH, getpid());
mkfifo(read_file, 0666);
mkfifo(write_file, 0666);
sprintf(msg, "%d\n", getpid());
write(fd_server, msg, strlen(msg));
fd_r = open(read_file, O_RDONLY);
fd_w = open(write_file, O_WRONLY);
key_t shm_key, sem_key ;
int my_shm, my_sem ;
char line[1024] ;
pMBUF p ;
shm_key = (key_t)atoi(argv[1]);
sem_key = (key_t)atoi(argv[2]);
my_shm = shmget(shm_key, sizeof(MBUF), 0666|IPC_CREAT);
my_sem = semget(sem_key, 1, 0666 | IPC_CREAT);
semctl(my_sem, 0, SETVAL, 1);
p = (pMBUF)shmat(my_shm, NULL, 0);
memset(p, 0, sizeof(MBUF));
while(memset(line, 0, 1024), fgets(line, 1024, stdin) != NULL)
{
write(fd_w, line, strlen(line));
memset(line, 0, 1024);
read(fd_r, line, 1024);
while( P(my_sem), p -> m_flag == 1)
{
V(my_sem);
sleep(1);
}
strcpy(p ->m_buf, line);
p ->m_flag = 1 ;
V(my_sem);
}
while( P(my_sem), p -> m_flag == 1)
{
V(my_sem);
sleep(1);
}
strcpy(p ->m_buf, "over");
p ->m_flag = 1 ;
V(my_sem);
sleep(3);
shmdt(p);
shmctl(my_shm, IPC_RMID, NULL) ;
semctl(my_sem, 0, IPC_RMID);
}
客戶端輸出端:
/*************************************************************************
> File Name: client_out.c
> Author: Comst
> Mail:[email protected]
> Created Time: Wed 04 Feb 2015 03:04:39 PM CST
************************************************************************/
#include "client.h"
int main(int argc, char* argv[])//shm_key sem_key
{
key_t shm_key, sem_key ;
int my_shm, my_sem ;
char line[1024] ;
pMBUF p ;
shm_key = atoi(argv[1]);
sem_key = atoi(argv[2]);
my_shm = shmget(shm_key, sizeof(MBUF), 0666);
my_sem = semget(sem_key, 1, 0666 );
semctl(my_sem, 0, SETVAL, 1);
p = (pMBUF)shmat(my_shm, NULL, 0);
memset(p, 0, sizeof(MBUF));
while(1)
{
while(P(my_sem), p -> m_flag == 0)
{
V(my_sem);
sleep(1);
}
printf("%d : %s\n", getpid(), p -> m_buf);
if(strcmp(p ->m_buf, "over") == 0)
{
V(my_sem);
break ;
}
p -> m_flag = 0 ;
V(my_sem);
}
shmdt(p);
}
功能函數:
/*************************************************************************
> File Name: ./func.c
> Author: Comst
> Mail:[email protected]
> Created Time: Wed 04 Feb 2015 03:17:06 PM CST
************************************************************************/
#include "client.h"
void P(int semid)
{
struct sembuf my_buf ;
memset(&my_buf, 0, sizeof(my_buf) );
my_buf.sem_num = 0 ;
my_buf.sem_op = -1 ;
my_buf.sem_flg = SEM_UNDO ;
semop(semid, &my_buf, 1);
}
void V(int semid)
{
struct sembuf my_buf ;
memset(&my_buf, 0, sizeof(my_buf) );
my_buf.sem_num = 0 ;
my_buf.sem_op = 1 ;
my_buf.sem_flg = SEM_UNDO ;
semop(semid, &my_buf, 1);
}
服務器:
/*************************************************************************
> File Name: server.c
> Author: Comst
> Mail:[email protected]
> Created Time: Wed 04 Feb 2015 04:40:58 PM CST
************************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<signal.h>
#define PATH "/home/comst/pipe"
#define NAME "server.fifo"
void child_handle(int sig_num)
{
printf("a child exit!\n");
wait(NULL);
}
void reverse(char* str)
{
int bg, end ;
char tmp ;
bg = 0 ;
end = strlen(str) - 1 ;
while(bg < end)
{
tmp = str[bg] ;
str[bg] = str[end] ;
str[end] = tmp ;
bg ++ ;
end -- ;
}
}
void child_main(int fd_rd, int fd_wr)
{
char buf[1024] ;
while(memset(buf, 0, 1024), read(fd_rd, buf, 1024) != 0)
{
reverse(buf);
write(fd_wr, buf, strlen(buf));
}
}
int main(int argc, char* argv[])
{
signal(17, child_handle);
char file_name[128] = "";
char client_r[128], client_w[128];
char line[32] ;
int fd_read ;
int client_id ;
int fd_cr , fd_cw ;
FILE* fp ;
sprintf(file_name, "%s/%s", PATH, NAME);
mkfifo(file_name, 0666) ;
fd_read = open(file_name, O_RDONLY);
open(file_name, O_WRONLY);
fp = fdopen(fd_read, "r");
while(memset(line, 0 , 32), fgets(line, 32, fp) != NULL)// "pid\n"
{// cr cw pid_r.fifo pid_w.fifo
sscanf(line, "%d", &client_id);
printf("client: %d request !\n", client_id) ;
memset(client_r, 0, 128);
memset(client_w, 0, 128);
sprintf(client_r, "%s/%d_r.fifo", PATH, client_id);
sprintf(client_w, "%s/%d_w.fifo", PATH, client_id);
fd_cw = open(client_r, O_WRONLY);
fd_cr = open(client_w, O_RDONLY);
if(fork() == 0)
{
child_main(fd_cr, fd_cw);
close(fd_cr);
close(fd_cw);
exit(1);
}
close(fd_cr);
close(fd_cw);
}
memset(file_name, 0, 128);
sprintf(file_name, "%s/%s", PATH, NAME);
unlink(file_name);
return 0 ;
}