进程间通信

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;
}

 

posted on 2024-10-01 10:07  轩邈、  阅读(9)  评论(0编辑  收藏  举报

导航