IPC溝通的有許多方式,例如:Shared Memory, Message Queue, PIPE, FIFO, Unix Socket 等等。 下面將會整理 Linux 下常見的 IPC 的運作方式舉例。
##一、Shared Memory 主要有四個 API:
用法說明:
舉例: 請參考 http://www.cs.cf.ac.uk/Dave/C/node27.html
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#define SHMSZ 27
main()
{
char c;
int shmid;
key_t key;
char* shm, *s;
/*
* We'll name our shared memory segment
* "5678".
*/
key = 5678;
/*
* Create the segment.
*/
if ((shmid = shmget(key, SHMSZ, IPC_CREAT | 0666)) < 0) {
perror("shmget");
exit(1);
}
/*
* Now we attach the segment to our data space.
*/
if ((shm = shmat(shmid, NULL, 0)) == (char*) - 1) {
perror("shmat");
exit(1);
}
/*
* Now put some things into the memory for the
* other process to read.
*/
s = shm;
for (c = 'a'; c <= 'z'; c++) {
*s++ = c;
}
*s = NULL;
/*
* Finally, we wait until the other process
* changes the first character of our memory
* to '*', indicating that it has read what
* we put there.
*/
while (*shm != '*') {
sleep(1);
}
exit(0);
}
/*
* shm-client - client program to demonstrate shared memory.
*/
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#define SHMSZ 27
main()
{
int shmid;
key_t key;
char* shm, *s;
/*
* We need to get the segment named
* "5678", created by the server.
*/
key = 5678;
/*
* Locate the segment.
*/
if ((shmid = shmget(key, SHMSZ, 0666)) < 0) {
perror("shmget");
exit(1);
}
/*
* Now we attach the segment to our data space.
*/
if ((shm = shmat(shmid, NULL, 0)) == (char*) - 1) {
perror("shmat");
exit(1);
}
/*
* Now read what the server put in the memory.
*/
for (s = shm; *s != NULL; s++) {
putchar(*s);
}
putchar('\n');
/*
* Finally, change the first character of the
* segment to '*', indicating we have read
* the segment.
*/
*shm = '*';
exit(0);
}
##二、Message Queue 的基本用法 參考 http://tldp.org/LDP/lpg/node27.html,主要有四個API
用法說明:
struct msgbuf
{
long mtype;
char mtext[1];
};
舉例:
#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]); 用法說明:
#include<unistd.h>
int fds[2];
int pipe(fds);
##四、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);
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);
/* server.c */
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
int port = 8111;
int main(void)
{
struct sockaddr_in sin;
struct sockaddr_in pin;
int mysock;
int tempsock;
int addrsize;
char str[100], str1[20], str2[20], str3[20];
char buf[100];
int i, len1, len2;
float c;
mysock = socket(AF_INET, SOCK_STREAM, 0);
if (mysock == -1) {
perror("call to socket");
exit(1);
}
bzero(&sin, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_port = htons(port);
if (bind(mysock, (struct sockaddr*)&sin, sizeof(sin)) == -1) {
perror("call to bind");
exit(1);
}
if (listen(mysock, 20) == -1) {
perror("call to listen");
exit(1);
}
printf("Accepting connections ...\n");
while (1) {
tempsock = accept(mysock, (struct sockaddr*)&pin, &addrsize);
if (tempsock == -1) {
perror("call to accept");
exit(1);
}
len1 = recv(tempsock, str, 100, 0);
printf("\n收到字元數: %d\n", len1);
str[len1] = 0;
printf("received from client: %s\n", str);
if (len1 > 0) {
strcpy(str1, strtok(str, " "));
printf("第 1 個字串為: %s\n", str1);
strcpy(str2, strtok(NULL, " "));
printf("第 2 個字串為: %s\n", str2);
strcpy(str3, strtok(NULL, " "));
printf("第 3 個字串為: %s\n", str3);
c = atof(str3) * 1.05;
sprintf(buf, "品號為 %s\n品名為 %s\n含稅價為: %.2f\n", str1, str2, c);
}
len2 = strlen(buf);
if (send(tempsock, buf, len2, 0) == -1) {
perror("call to send");
exit(1);
}
close(tempsock);
}
return 0;
}
/* client.c */
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
int port = 8111;
int main(int argc, char* argv[])
{
struct sockaddr_in pin;
int mysock;
char buf[8192];
char* str = "A001 電視機 20000.00 ";
if (argc < 2) {
printf("使用方法: client 字串\n");
printf("使用預設字串\n");
} else {
str = argv[1];
}
bzero(&pin, sizeof(pin));
pin.sin_family = AF_INET;
pin.sin_addr.s_addr = inet_addr("192.168.2.163");
pin.sin_port = htons(port);
mysock = socket(AF_INET, SOCK_STREAM, 0);
if (mysock == -1) {
perror("call to socket");
exit(1);
}
if (connect(mysock, (void*)&pin, sizeof(pin)) == -1) {
perror("call to connect");
exit(1);
}
printf("Sending message %s to server ...\n", str);
if (send(mysock, str, strlen(str), 0) == -1) {
perror("Error in send\n");
exit(1);
}
if (recv(mysock, buf, 8192, 0) == -1) {
perror("Error in receiving\n");
exit(1);
}
printf("\nResponse from server: \n\n%s\n", buf);
close(mysock);
return 0;
}
請直接參考 http://learn.akae.cn/media/ch37s04.html 舉例:
##請參考 http://learn.akae.cn/media/ch37s04.htmlhttp://www.cs.cf.ac.uk/Dave/C/node28.html
##參考資料: