程式間通訊

junnyblog發表於2009-10-08

結合個人開發經驗,講訴多程式程式設計,並結合oracle程式管理進行探討.整理時間:2009-11-01 至2009-11-30

-------這段時間一直在研究足球彩票,以至於沒時間更新blog,這是以前總結部分內容,暫時放上來.......

[@more@]

IPC(InterProcess Communication)主要包括:管道、FIFO、資訊佇列、訊號量及共享記憶體等。不包括Socket。
1、管道
優點:半雙工管道是最常用的,如shell管道。
缺點:a、以前以半雙工的方式存在,現在個別系統提供全雙工方式;b、只能父子程式之間通訊。
應用簡單說明:
(1)建立管道pipe(filedes[2]),其中filedes[0]讀read(filedes[0],buf,sizeof(buf));filedes[1]寫 write(filedes[1],s,sizeof(s))
(2)管道方向:父程式->子程式 父程式關閉讀filedes[0];子程式關閉寫filedes[1];反之成立。
#include
#include

int main( void )
{
int filedes[2];
char buf[80];
pid_t pid;
char buf2[80];
pipe( filedes );

if ( (pid=fork()) > 0 )
{
printf( "This is in the father process,here write a string to the pipe.n" );
char s[] = "Hello world , this is write by pipe.n";
close( filedes[0] );
write( filedes[1], s, sizeof(s) );
}
else
{
printf( "This is in the child process,here read a string from the pipe.n" );
close( filedes[1] );
read( filedes[0], buf, sizeof(buf) );
printf( "%sn", buf );
}
waitpid( pid, NULL, 0 );
return 0;
}

2、FIFO(命名管道)
優點:不相關程式進行交換資料,區別於管道侷限於父子程式。一般檔案I/O函式都可用於FIFO
缺點:
應用簡單說明:
(1)建立FIFO mkfifo(const char *pathname,mode_t mode);開啟管道open(FIFO,O_RDONLY|O_NONBLOCK,0); 讀read,寫write同檔案操作。
#include
#include
#include
#include
#include
#include
#include

/*FIFO管道路徑*/
#define FIFO_SERVER "/tmp/myfifo"

int main(int argc,char** argv)
{
int fd = 0;
char w_buf[100];
int nwrite;
/*開啟FIFO管道*/
fd=open(FIFO_SERVER,O_WRONLY|O_NONBLOCK,0);
if(fd==-1)
if(errno==ENXIO)
printf("open error; no reading processn");
/*判斷有沒有引數輸入*/
if(argc==1)
printf("Please send somethingn");
/*複製引數輸入*/
strcpy(w_buf,argv[1]);
/*寫到FIFO去*/
if((nwrite=write(fd,w_buf,100))==-1)
{
if(errno==EAGAIN)
printf("The FIFO has not been read yet.Please try latern");
}
else
/*輸出寫入的內容*/
{
printf("write %s to the FIFOn",w_buf);
}
return 0;
}

[etl@localhost FIFO]$ ls
client.cpp
[etl@localhost FIFO]$ cat >server.cpp
#include
#include
#include
#include
#include
#include
#include

/*定義FIFO路徑*/
#define FIFO "/tmp/myfifo"

main(int argc,char** argv)
{
char buf_r[100];
int fd;
int nread;
/*建立FIFO管道*/
if((mkfifo(FIFO,O_CREAT|O_EXCL)<0)&&(errno!=EEXIST))
printf("cannot create fifoservern");
printf("Preparing for reading bytes...n");

memset(buf_r,0,sizeof(buf_r));
/*開啟FIFO管道,不阻塞方式*/
fd=open(FIFO,O_RDONLY|O_NONBLOCK,0);
if(fd==-1)
{
perror("open");
exit(1);
}
while(1)
{
memset(buf_r,0,sizeof(buf_r));
/*讀管道,因為定義了非阻塞方式,故在此不會阻塞程式*/
if((nread=read(fd,buf_r,100))==-1){
if(errno==EAGAIN)
printf("no data yetn");
}
printf("read %s from FIFOn",buf_r);
sleep(1);
}
pause();
unlink(FIFO);
}

3、訊息佇列

應用簡單說明:一般應用為主程式每發起一個任務,生成一個子程式處理任務並反回處理結果。
#include
#include
#include
#include
#include
#include
static struct msgbuf1
{
long mtype;
char mtext[100];
} sndbuf, rcvbuf, *msgp ;

extern int errno;

int main(int argc, char **argv)
{
int rtrn, msqid ;
char name[10];
double balance;

if (argc!=2)
{
fprintf(stderr,"msgreq [01-99]n"); exit(-1);
}
if ((msqid = msgget(0x888, IPC_CREAT|0660)) == -1 )
{
fprintf(stderr, "msgget 888 failed !n");
//exit(-1);
}
msgp=&sndbuf;

sprintf(sndbuf.mtext,"%2.2s",argv[1]);
printf("輸入4位帳號:");
scanf("%s",&sndbuf.mtext[2]);

sndbuf.mtext[6]=0;
msgp->mtype=666;
rtrn=msgsnd(msqid,msgp, strlen(sndbuf.mtext), 0);
if (rtrn==-1)
{
perror("msgsnd"); exit(-1);
}
msgp=&rcvbuf;

fprintf(stderr,"等待後臺資料處理程式的回答....");

rtrn=msgrcv(msqid,msgp, 100, atoi(argv[1]), 0);
if(rtrn==-1)
{
perror("msgrcv"); exit(-1);
}

sscanf(rcvbuf.mtext,"%[^|]|%lf",name,&balance);
printf("n姓名=%sn",name);
printf("餘額=%lfn",balance);
}

/*服務方程式msgcenter.c*/
#include
#include
#include
#include
#include
#include

static struct msgbuf1
{
long mtype;
char mtext[100];
} sndbuf, rcvbuf , *msgp;

extern int errno;

int main()
{
int rtrn, msqid ;
char strbuf[100];

if ( (msqid = msgget(0x888, IPC_CREAT|0600)) == -1 )
{
fprintf(stderr, "msgget 888 failed !n"); exit(-1);
}

while(1)
{
msgp=&rcvbuf;
fprintf(stderr,"等待前臺程式的請求....");

rtrn=msgrcv(msqid, msgp, 100, 666 ,MSG_NOERROR);
if(rtrn==-1)
{
perror("msgrcv");exit(-1);
}
msgp=&sndbuf;
sprintf(strbuf,"%2.2s",rcvbuf.mtext);
msgp->mtype=atoi(strbuf);
printf("n輸入帳號=%4.4s的帳戶姓名:",&rcvbuf.mtext[2]);

scanf("%s",sndbuf.mtext);
strcat(sndbuf.mtext,"|");
printf("輸入該帳戶餘額:");
scanf("%s",strbuf);
strcat(sndbuf.mtext,strbuf);
rtrn=msgsnd(msqid,msgp, strlen(sndbuf.mtext), 0);
if (rtrn==-1)
{
perror("msgsnd");
exit(-1);
}
}
}

4、訊號量
5、共享記憶體


#include
#include
#include

struct lcd_info {
int width; // 屏寬
int height; // 屏高
int depth; // 每點畫素數
int line_bytes; // 每行位元組數
int data_offset;// 資料區開始偏移值
};

int shmId;

int main(void)
{
int data_size;
void *data;
struct lcd_info lcd;
struct shmid_ds shm;

key_t key = ftok("/sbin/init", 'g');
// 根據init檔案的ino節點號,dev裝置號,和id組合出一個key序列串,作為唯一key標識[luthr.gliethttp]
// ftok庫實現為
// key_t ftok(const char* path, int id)
// {
// struct stat st;
// if ( lstat(path, &st) < 0 )
// return -1;
// return (key_t)( (st.st_ino & 0xffff) | ((st.st_dev & 0xff) << 16) | ((id & 255) << 24) );
// }

lcd.width = 800;
lcd.height = 600;
lcd.depth = 16;
lcd.line_bytes = lcd.width * ((lcd.depth+7) >> 3);
lcd.data_offset = 512;
data_size = lcd.line_bytes*lcd.height + lcd.data_offset; // 0-511位元組存放控制資訊[luther.gliethttp]
// 跳過前512位元組的控制資訊空間[luther.gliethttp]

shmId = shmget( key, data_size, IPC_CREAT|0666); // 建立一個data_size大小的共享記憶體,該共享記憶體
// 對應的唯一索引值為key,呼叫shmget(key, 0, 0);可以獲得該共享記憶體[luther.gliethttp]
if ( shmId != -1 )
data = (unsigned char *)shmat( shmId, 0, 0 );
else {
shmctl( shmId, IPC_RMID, &shm ); // 刪除已經存在的key相同的共享記憶體[luther.gliethttp].
shmId = shmget( key, data_size, IPC_CREAT|0666);
data = (unsigned char *)shmat( shmId, 0, 0 );
}

if ((int)data == -1) {
printf("Error : shmgetn");
return -1;
}

*((struct lcd_info*)data) = lcd;

for (;;) {
sleep(1);
}

shmctl( shmId, IPC_RMID, &shm ); // 刪除共享記憶體,當然這裡是不會執行到這了,應該在signal回撥函式中執行,不過再次啟動的時候,會自動刪除[luther.gliethttp].
return 0;
}


#include
#include
#include

struct lcd_info {
int width; // 屏寬
int height; // 屏高
int depth; // 每點畫素數
int line_bytes; // 每行位元組數
int data_offset;// 資料區開始偏移值
};

int shmId;

int main(void)
{
struct lcd_info *lcd;

key_t key = ftok("/sbin/init", 'g');
// 根據init檔案的ino節點號,dev裝置號,和id組合出一個key序列串,作為唯一key標識[luthr.gliethttp]
// ftok庫實現為
// key_t ftok(const char* path, int id)
// {
// struct stat st;
// if ( lstat(path, &st) < 0 )
// return -1;
// return (key_t)( (st.st_ino & 0xffff) | ((st.st_dev & 0xff) << 16) | ((id & 255) << 24) );
// }

shmId = shmget(key, 0, 0);
if (shmId != -1)
lcd = shmat(shmId, 0, 0);
else {
printf("[luther.gliethttp] shmId=-1n");
return -1;
}

printf("=====[luther.gliethttp.lcd.info]=====n"
"widthtt= %dn"
"heighttt= %dn"
"depthtt= %dn"
"line_bytest= %dn"
"data_offsett= %dn",
lcd->width,
lcd->height,
lcd->depth,
lcd->line_bytes,
(unsigned int)lcd->data_offset);
return 0;
}

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/22630256/viewspace-1027636/,如需轉載,請註明出處,否則將追究法律責任。

相關文章