/**
*IPC是指進程間的通訊,其中有三種我們稱之為IPC即訊息佇列、訊號量以及共用儲存空間
*建立IPC結構(調用msgget\semget\shmget), 應指定一個鍵,鍵的資料類型是基本系統資料類型key_t,鍵由核心變換成標識符
*以下是訊息佇列msgget
*/
/**
* 優缺點:IPC結構是在系統範圍內起作用的,沒有訪問計數。例如,如果進程建立了一個訊息佇列,在該隊列中放入了幾則訊息,
* 然後終止,但是該訊息佇列及其內容並不會被刪除,它們餘留在系統中直至出現下述情況:
* 由某個進程調用msgrcv或msgctl讀取訊息或刪除訊息佇列,或某個進程執行ipcrm命令刪除訊息佇列,
* 或由正在再啟動的系統刪除訊息佇列,將此與管道相比,當最後一個訪問管道的進程終止時,管道就被完全地刪除了。
* 對於FIFO而言,雖然當最後一個引用FIFO進程終止時其名字仍保留在系統中,直至顯式地刪除它,但是留在FIFO中的資料卻在此時被全部刪除,於是也就徒有虛名了。
* XSI IPC的另一個問題是這些IPC結構在檔案系統中沒有名字,我們不能使用那些使用檔案系統的函數來訪問它們或修改他們的屬性。
* 為了支援它們不得不增加了十幾條全新的系統調用(msgget,semop,shmat).我們不能用ls命令見到IPC對象,不能用rm命令刪除他們,
* 不能用chmod命令修改它們的存取權限。於是就不得不增加新的命令ipcs和ipcrm.
*/
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <pthread.h>
#define MY_KEY 8800811 // need to change
#define SERVER_ID 2
#define MAX_BUF 200
void sigend(int);
//訊息結構體
struct mymsg {
long mtype;
long pid;
char buf[MAX_BUF]; //在此指定了共用記憶體的大小 = MAX_BUF+ 8
};
int msgid;
bool isWorking = true;
#define SERVER_TYPE 5555
#define CLIENT_TYPE 6666
//阻塞式接收資料
void * RunRecvData(void * pVoid)
{
//指定接收類型--對應 發送結構體mymsg.mtype內容
long *typ = (long*)pVoid;
struct mymsg msgbuf;
while(isWorking)
{
//接收訊息;
msgrcv(msgid, &msgbuf, sizeof(struct mymsg), *typ, 0);
printf("recv data: %s, type=%ld, pid= %ld \n", msgbuf.buf, msgbuf.mtype, msgbuf.pid);
}
return NULL;
}
int main3(void)
{
pthread_t pidRecv;
struct mymsg msgbuf; //定義一結構變數
//建立新的訊息佇列
if ((msgid = msgget(MY_KEY, IPC_CREAT | IPC_EXCL | 0666)) < 0)
{
//建立失敗,已經存在,直接擷取訊息id,擷取已有的訊息佇列
msgid = msgget(MY_KEY, 0666);
printf("Act as client, ask question and wait answer! msgid=%d\n", msgid);
printf("To end this process, enter end as input question.\n\n");
pid_t pid = getpid();
long type = SERVER_TYPE;
pthread_create(&pidRecv,NULL,RunRecvData,&type);
//I/O中斷
printf("Input question in one line:\n");
fgets(msgbuf.buf, sizeof(struct mymsg) - 2 * sizeof(long) - 1, stdin);
while (strcmp(msgbuf.buf, "end\n"))
{
//獲得服務進程號
msgbuf.mtype = CLIENT_TYPE;// SERVER_ID;
//獲得當前進程的進程號
msgbuf.pid = getpid();
//發送訊息;
msgsnd(msgid, &msgbuf, sizeof(struct mymsg) - sizeof(long), 0);
printf("Input question in one line:\n");
memset(msgbuf.buf,0,sizeof(msgbuf.buf));
fgets(msgbuf.buf, sizeof(struct mymsg) - 2 * sizeof(long) - 1,
stdin);
}
}
else
{
//設定某一訊號的對應動作, sigend 刪除標記
signal(SIGINT, sigend);
signal(SIGTERM, sigend);
printf("ACT SERVER!!! Wait question and give answer. msgid=%d\n", msgid);
printf("To end this process, try Ctrl+C or use kill.\n\n");
long tmpId = CLIENT_TYPE;
pthread_create(&pidRecv,NULL,RunRecvData,&tmpId);
while (1)
{
memset(msgbuf.buf,0,sizeof(msgbuf.buf));
fgets(msgbuf.buf, sizeof(struct mymsg) - 2 * sizeof(long) - 1,
stdin);
msgbuf.mtype = SERVER_TYPE; //msgbuf.pid;
msgbuf.pid = getpid();
//發送訊息;
msgsnd(msgid, &msgbuf, sizeof(struct mymsg) - sizeof(long), 0);
}
}
}
void sigend(int sig)
{
//操縱一個訊息佇列;
//IPC_RMID:從系統核心中移走訊息佇列。
//IPC_STAT:讀取訊息佇列的資料結構msqid_ds,並將其儲存在buf指定的地址中。 可以直接拷貝,減少記憶體複製
//IPC_SET:設定訊息佇列的資料結構msqid_ds中的ipc_perm元素的值。這個值取自buf參數。
if(0==msgctl(msgid, IPC_RMID, 0))
printf("msgctl:success\n");
else{
//列印錯誤資訊
}
exit(0);
}