进程间通信
1、使用IPC信号
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <fcntl.h>
#include <signal.h>
void sigHandler(int sig);
/* moved these variables to the global scope
since they need to be access/deleted/closed
from the signal handler */
FILE *fp;
const char pidfile[] = "/var/run/my-daemon.pid";
int main(void)
{
pid_t pid;
time_t now; /* for the current time */
struct sigaction action; /* for sigaction */
const char daemonfile[] = "/tmp/my-daemon-is-alive.txt";
if ( ( pid = fork() ) == -1 ) /* 创建子进程 */
{
perror("Can't fork");
return 1;
}
else if ( (pid != 0) ) /* 父进程退出 */
{
exit(0);
}
/* the parent process has exited, which makes the rest of
the code the child process */
setsid(); /* create a new session to lose the controlling
terminal 创建会话脱离终端 */
/* fork again, creating a grandchild, the actual daemon */
if ( (pid = fork()) == -1 ) /* 子进程中创建孙子进程 */
{
perror("Can't fork");
return 1;
}
/* the child process which will exit */
else if ( pid > 0 )/* 子进程中打开pidfile,然后写入孙子进程号,最后子进程退出 */
{
/* open pid-file for writing and error check it */
if ( (fp = fopen(pidfile, "w")) == NULL )
{
perror("Can't open file for writing");
return 1;
}
fprintf(fp, "%d\n", pid); /* write pid to file */
fclose(fp); /* close the file pointer */
exit(0);
}
umask(022); /* reset the umask to something sensible */
chdir("/"); /* change working directory to open the "daemonfile" for writing */
if ( (fp = fopen(daemonfile, "w")) == NULL )
{
perror("Can't open daemonfile");
return 1;
}
/* from here, we don't need stdin, stdout or, stderr
anymore, so let's close them all, then re-open them
to /dev/null */
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
open("/dev/null", O_RDONLY); /* 0 = stdin */
open("/dev/null", O_WRONLY); /* 1 = stdout */
open("/dev/null", O_RDWR); /* 2 = stderr */
/* prepare for sigaction */
action.sa_handler = sigHandler;
sigfillset(&action.sa_mask);
action.sa_flags = SA_RESTART;
/* register the signals we want to handle */
sigaction(SIGTERM, &action, NULL);
sigaction(SIGINT, &action, NULL);
sigaction(SIGQUIT, &action, NULL);
sigaction(SIGABRT, &action, NULL);
/* here we start the daemons "work" */
for (;;)
{
/* get the current time and write it to the
"daemonfile" that we opened above */
time(&now);
fprintf(fp, "Daemon alive at %s", ctime(&now));
fflush(fp); /* flush the stream */
sleep(30);
}
return 0;
}
void sigHandler(int sig)
{
int status = 0;
if ( sig == SIGTERM || sig == SIGINT
|| sig == SIGQUIT
|| sig == SIGABRT )
{
/* remove the pid-file */
if ( (unlink(pidfile)) == -1 )
status = 1;
if ( (fclose(fp)) == EOF )
status = 1;
exit(status); /* exit with the status set */
}
else /* some other signal */
{
exit(1);
}
}
2、使用管道通信
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#define MAX 128
int main(void)
{
int pipefd[2] = { 0 };
pid_t pid;
char line[MAX];
if ( (pipe(pipefd)) == -1 )
{
perror("Can't create pipe");
return 1;
}
if ( (pid = fork()) == -1 )
{
perror("Can't fork");
return 1;
}
if (pid > 0)
{
/* inside the parent */
close(pipefd[0]); /* close the read end */
dprintf(pipefd[1], "Hello from parent");
}
else
{
/* inside the child */
close(pipefd[1]); /* close the write end */
read(pipefd[0], line, MAX-1);
printf("%s\n", line); /* print message from
* the parent */
}
return 0;
}
3、FIFO-命名管道
FIFO构建发送者
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
#include <errno.h>
void cleanUp(int signum);
int fd; /* the FIFO file descriptor */
const char fifoname[] = "/tmp/my-2nd-fifo";
int main(int argc, char *argv[])
{
struct sigaction action; /* for sigaction */
if ( argc != 2 )
{
fprintf(stderr, "Usage: %s 'the message'\n",
argv[0]);
return 1;
}
/* prepare for sigaction and register signals
* (for cleanup when we exit) */
action.sa_handler = cleanUp;
sigfillset(&action.sa_mask);
action.sa_flags = SA_RESTART;
sigaction(SIGTERM, &action, NULL);
sigaction(SIGINT, &action, NULL);
sigaction(SIGQUIT, &action, NULL);
sigaction(SIGABRT, &action, NULL);
sigaction(SIGPIPE, &action, NULL);
if ( (mkfifo(fifoname, 0644)) != 0 )
{
perror("Can't create FIFO");
return 1;
}
if ( (fd = open(fifoname, O_WRONLY)) == -1)
{
perror("Can't open FIFO");
return 1;
}
while(1)
{
dprintf(fd, "%s\n", argv[1]);
sleep(1);
}
/* just in case, but we shouldn't reach this */
close(fd);
unlink(fifoname);
return 0;
}
void cleanUp(int signum)
{
if (signum == SIGPIPE)
printf("The receiver stopped receiving\n");
else
printf("Aborting...\n");
if ( (close(fd)) == -1 )
perror("Can't close file descriptor");
if ( (unlink(fifoname)) == -1)
{
perror("Can't remove FIFO");
exit(1);
}
exit(0);
}
FIFO构建接收者
#include <stdio.h>
int main(void)
{
FILE *fp;
signed char c;
const char fifoname[] = "/tmp/my-2nd-fifo";
if ( (fp = fopen(fifoname, "r")) == NULL )
{
perror("Can't open FIFO");
return 1;
}
while ( (c = getc(fp)) != EOF )
putchar(c);
fclose(fp);
return 0;
}
4、消息队列
1、构建发送者
#include <stdio.h>
#include <mqueue.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#define MAX_MSG_SIZE 2048
int main(int argc, char *argv[])
{
int md; /* msg queue descriptor */
/* attributes for the message queue */
struct mq_attr msgattr;
msgattr.mq_maxmsg = 10;
msgattr.mq_msgsize = MAX_MSG_SIZE;
if ( argc != 2)
{
fprintf(stderr, "Usage: %s 'my message'\n",
argv[0]);
return 1;
}
md = mq_open("/my_queue", O_CREAT|O_RDWR, 0644,
&msgattr);
if ( md == -1 )
{
perror("Creating message queue");
return 1;
}
if ( (mq_send(md, argv[1], strlen(argv[1]), 1))
== -1 )
{
perror("Message queue send");
return 1;
}
mq_close(md);
return 0;
}
2、构建接收者
#include <stdio.h>
#include <mqueue.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
int md; /* msg queue descriptor */
char *buffer;
struct mq_attr msgattr;
md = mq_open("/my_queue", O_RDONLY);
if (md == -1 )
{
perror("Open message queue");
return 1;
}
if ( (mq_getattr(md, &msgattr)) == -1 )
{
perror("Get message attribute");
return 1;
}
buffer = calloc(msgattr.mq_msgsize,
sizeof(char));
if (buffer == NULL)
{
fprintf(stderr, "Couldn't allocate memory");
return 1;
}
printf("%ld messages in queue\n",
msgattr.mq_curmsgs);
for (int i = 0; i<msgattr.mq_curmsgs; i++)
{
if ( (mq_receive(md, buffer,
msgattr.mq_msgsize, NULL)) == -1 )
{
perror("Message receive");
return 1;
}
printf("%s\n", buffer);
memset(buffer, '\0', msgattr.mq_msgsize);
}
free(buffer);
mq_close(md);
mq_unlink("/my_queue");
return 0;
}
5、共享内存
5.1 在父子进程中互相通信
#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define DATASIZE 128
int main(void)
{
char *addr;
int status;
pid_t pid;
const char startmsg[] = "Hello, we are running";
const char childmsg[] = "Hello from child";
const char parentmsg[] = "New msg from parent";
addr = mmap(NULL, DATASIZE,
PROT_WRITE | PROT_READ,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (addr == MAP_FAILED)
{
perror("mmap");
return 1;
}
memcpy(addr, startmsg, strlen(startmsg) + 1);
printf("Parent PID is %d\n", getpid());
printf("Original message: %s\n", addr);
if ( (pid = fork()) == -1 )
{
perror("Can't fork");
return 1;
}
if (pid == 0)
{
/* child */
memcpy(addr, childmsg, strlen(childmsg) + 1);
}
else if(pid > 0)
{
/* parent */
waitpid(pid, &status, 0);
printf("Child executed with PID %d\n", pid);
printf("Message from child: %s\n", addr);
memcpy(addr, parentmsg,
strlen(parentmsg) + 1);
printf("Parent message: %s\n", addr);
}
munmap(addr, DATASIZE);
return 0;
}
5.2 在不相关的进程之间利用共享内存进行通信
创建写者
#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define DATASIZE 128
int main(void)
{
int fd;
float *addr;
const char memid[] = "/my_memory";
const float numbers[3] = { 3.14, 2.718, 1.202};
/* create shared memory file descriptor */
if ( (fd = shm_open(memid,
O_RDWR | O_CREAT, 0600)) == -1)
{
perror("Can't open memory fd");
return 1;
}
/* truncate memory to DATASIZE */
if ( (ftruncate(fd, DATASIZE)) == -1 )
{
perror("Can't truncate memory");
return 1;
}
/* map memory using our file descriptor */
addr = mmap(NULL, DATASIZE, PROT_WRITE,
MAP_SHARED, fd, 0);
if (addr == MAP_FAILED)
{
perror("Memory mapping failed");
return 1;
}
/* copy data to memory */
memcpy(addr, numbers, sizeof(numbers));
/* wait for enter */
printf("Hit enter when finished ");
getchar();
/* clean up */
munmap(addr, DATASIZE);
shm_unlink(memid);
return 0;
}
创建读者
#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define DATASIZE 128
int main(void)
{
int fd;
float *addr;
const char memid[] = "/my_memory";
float numbers[3];
/* open memory file descriptor */
fd = shm_open(memid, O_RDONLY, 0600);
if (fd == -1)
{
perror("Can't open file descriptor");
return 1;
}
/* map shared memory */
addr = mmap(NULL, DATASIZE, PROT_READ,
MAP_SHARED, fd, 0);
if (addr == MAP_FAILED)
{
perror("Memory mapping failed");
return 1;
}
/* read the memory and print the numbers */
memcpy(numbers, addr, sizeof(numbers));
for (int i = 0; i<3; i++)
{
printf("Number %d: %.3f\n", i, numbers[i]);
}
return 0;
}
6、套接字通信
6.1 构建发送者
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <errno.h>
#define MAXLEN 128
void cleanUp(int signum);
const char sockname[] = "/tmp/my_1st_socket";
int connfd;
int datafd;
int main(void)
{
int ret;
struct sockaddr_un addr;
char buffer[MAXLEN];
struct sigaction action;
/* prepare for sigaction */
action.sa_handler = cleanUp;
sigfillset(&action.sa_mask);
action.sa_flags = SA_RESTART;
/* register the signals we want to handle */
sigaction(SIGTERM, &action, NULL);
sigaction(SIGINT, &action, NULL);
sigaction(SIGQUIT, &action, NULL);
sigaction(SIGABRT, &action, NULL);
sigaction(SIGPIPE, &action, NULL);
/* create socket file descriptor */
connfd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
if ( connfd == -1 )
{
perror("Create socket failed");
return 1;
}
/* set address family and socket path */
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, sockname);
/* bind the socket (we must cast our sockaddr_un
* to sockaddr) */
if ( (bind(connfd, (const struct sockaddr*)&addr,
sizeof(struct sockaddr_un))) == -1 )
{
perror("Binding socket failed");
return 1;
}
/* prepare for accepting connections */
if ( (listen(connfd, 20)) == -1 )
{
perror("Listen error");
return 1;
}
/* accept connection and create new file desc */
datafd = accept(connfd, NULL, NULL);
if (datafd == -1 )
{
perror("Accept error");
return 1;
}
printf("Client connected\n");
while(1) /* main loop */
{
while(1) /* receive message, line by line */
{
ret = read(datafd, buffer, MAXLEN);
if ( ret == -1 )
{
perror("Error reading line");
cleanUp(1);
}
else if ( ret == 0 )
{
printf("Client disconnected\n");
cleanUp(1);
}
else
{
printf("Message: %s\n", buffer);
break;
}
}
/* write a confirmation message */
write(datafd, "Message received\n", 18);
}
return 0;
}
void cleanUp(int signum)
{
printf("Quitting and cleaning up\n");
close(connfd);
close(datafd);
unlink(sockname);
exit(0);
}
6.2 构建接收者
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <errno.h>
#define MAXLEN 128
int main(void)
{
const char sockname[] = "/tmp/my_1st_socket";
int fd;
struct sockaddr_un addr;
char sendbuffer[MAXLEN];
char recvbuffer[MAXLEN];
/* create socket file descriptor */
fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
if ( fd == -1 )
{
perror("Create socket failed");
return 1;
}
/* set address family and socket path */
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, sockname);
/* connect to the server */
if ( (connect(fd, (const struct sockaddr*) &addr,
sizeof(struct sockaddr_un))) == -1 )
{
perror("Can't connect");
fprintf(stderr, "The server is down?\n");
return 1;
}
while(1) /* main loop */
{
/* send message to server */
printf("Message to send: ");
fgets(sendbuffer, sizeof(sendbuffer), stdin);
sendbuffer[strcspn(sendbuffer, "\n")] = '\0';
if ( (write(fd, sendbuffer,
strlen(sendbuffer) + 1)) == -1 )
{
perror("Couldn't write");
break;
}
/* read response from server */
if ( (read(fd, recvbuffer, MAXLEN)) == -1 )
{
perror("Can't read");
return 1;
}
printf("Server said: %s\n", recvbuffer);
}
return 0;
}