2013年6月29日 星期六

Linux 下 IPC 的運作方式


IPC溝通的有許多方式,例如:Shared Memory, Message Queue, PIPE, FIFO, Unix Socket 等等。
下面將會整理 Linux 下常見的 IPC 的運作方式舉例。



一、Shared Memory
主要有四個 API: 
  • int shmget(key_t key, size_t size, int shmflg);
  • int shmctl(int shmid, int cmd, struct shmid_ds *buf); 
  • void *shmat(int shmid, const void *shmaddr, int shmflg); 
  • int shmdt(const void *shmaddr); 
用法說明:
  1. 使用函數 key_t ftok(char *name, int id) 取得一個在此系統內唯一的值,假設為 vKey。
  2. 使用函數 vShmId = shmget(vKey, 1024, 0600)取得一個大小為1024bytes, 權限為 0600(read+write) 的Shared Memory 。
  3. 使用函數 pShmPtr = shmat(vShmId,0,0) 取得 Shared Memory 對應的指標,以供後續操作。
  4. 當不需要使用時,使用 shmctl(vShmId, IPC_RMID, 0) 移除此 Shared Memory 。
舉例: 
請參考 http://www.cs.cf.ac.uk/Dave/C/node27.html 

二、Message Queue 的基本用法
參考  http://tldp.org/LDP/lpg/node27.html,主要有四個API
  • int msgget ( key_t key, int msgflg );
  • int msgsnd ( int msqid, struct msgbuf *msgp, int msgsz, int msgflg );
  • int msgrcv ( int msqid, struct msgbuf *msgp, int msgsz, long mtype, int msgflg );
  • int msgctl ( int msgqid, int cmd, struct msqid_ds *buf );
用法說明:
  1. 使用函數 key_t ftok(char *name, int id) 取得一個在此系統內唯一的值,假設為 vKey。當然這個值也可以自行指定。
  2. 使用函數 vQueueId = msgget( vKey, IPC_CREAT | 0660 ) 取得此 message queue 對應的 ID。
  3. 定義將傳送的 message 資料結構,假設是 tMsgBuf vxMsgBuf。此處需注意的是第一個欄位需定義為 long mtype, 舉例如下:
    struct msgbuf
    {
      long mtype;
      char mtext[1];
    };
     
  4. 使用函數 msgsnd(vQueueId, &vxMsgBuf, sizeof(tMsgBuf), 0) 將資料送往 message queue。
  5. 使用函數 msgrcv(vQueueId, &vxMsgBuf, sizeof(tMsgBuf), mtype, 0)) 取得 message queue 內, 定義為 mtype 的資料。
舉例:
#define MSG_KEY 9999
#define MSG_SIZE 1024
struct tMsgBuf
{
     long mtype;
     char mtext[MSG_SIZE];
};
typedef struct tMsgBuf tMessageBuffer; 
main()
{
     tMessageBuffer  sndmsg={0} ;
     tMessageBuffer  recvmsg={0}  ;
     msqid = msgget(MSG_KEY , PERMS | IPC_CREAT));
     msgsnd(msqid, &sndmsg, MSG_SIZE, 0);
     msgrcv(msqid, &recvmsg, MSG_SIZE, 0, 0)
}
三、PIPE
只需要一個 API,但是其只適用於 parent process 與 child process
int pipe(int fd[2]);
用法說明:
  1. 使用 pipe() 建立兩個 file descripter,第一個 FD 用來從PIPE讀取資料,第二個FD 用來作為寫入資料至PIPE,如下例: 
  2. #include<unistd.h>
    int fds[2];
    int pipe(fds);
  3. 接著呼叫 fork ,因為child process 會擁有同樣的 FD,因此便可以透過這兩個 FD 進行溝通。
舉例:
請參考
http://www.vr.ncue.edu.tw/esa/EmbeddedSystemProgramming2010/ch05.htm

 四、FIFO (Named Pipe)
使用以下幾個 API
int mkfifo(const char *pathname, mode_t mode);
int open(const char *pathname, int flags);
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
int close(int fd);
int unlink(const char *pathname);
用法說明:
1. 定義 FIFO 對應的檔案
int client_to_server;
char *myfifo = "/tmp/client_to_server_fifo";
int server_to_client;
char *myfifo2 = "/tmp/server_to_client_fifo";
2. 使用 mknod 或 mkfifo 建立 FIFO 對應的檔案
mkfifo(myfifo, 0666);
mkfifo(myfifo2, 0666);
3. 開啟檔案以供讀取或寫入
client_to_server = open(myfifo, O_RDONLY);
server_to_client = open(myfifo2, O_WRONLY); 
4. 寫入資料,或讀取資料
read(client_to_server, buf, BUFSIZ);
write(server_to_client,buf,BUFSIZ);
5. 關閉檔案,並刪除 FIFO 檔案
close(client_to_server);
close(server_to_client);
unlink(myfifo);
unlink(myfifo2);
舉例:
請參考
http://stackoverflow.com/questions/8611035/proper-fifo-client-server-connection

五、Unix Socket
此處socket應用與一般撰寫網路應用相同,只是此時改成使用AF_UNIX address family,設定的資訊由 sockaddr_in 的 port, address 改為 sockaddr_un 的 path 
可能會用到的 API 列舉如下: 
sockfd = socket(int socket_family, int socket_type, int protocol);
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int listen(int sockfd, int backlog);
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int send(int s, const char *msg, int len, int flags),
int recv(int s, char *buf, int len, int flags)
int close(int fd);
用法說明:
請直接參考 http://learn.akae.cn/media/ch37s04.html
舉例:
請參考
http://learn.akae.cn/media/ch37s04.htmlhttp://www.cs.cf.ac.uk/Dave/C/node28.html 

參考資料:
  1. Shared Memory http://www.cs.cf.ac.uk/Dave/C/node27.html
  2. Message Queue http://tldp.org/LDP/lpg/node27.html
  3. PIPE http://www.vr.ncue.edu.tw/esa/EmbeddedSystemProgramming2010/ch05.htm
  4. 取得 key http://www.360doc.com/content/11/1125/09/1317564_167200026.shtml