ipc programing sample in C

프로세스 통신관련 샘플을 C언어로 짜 봤다.

실행방법은 제일 먼저 데몬을 띄워놓고 다른 프로세스가 뜬 다음에 “start”파라미터를 추가하여 실행하면 프로세스간에 숫자를 하나씩 증가하는 소스이다. 이 소스도 2곳에 문제가 있다. start를 여러곳에서 실행하면 중복으로 그값을 전달한다. 그리고 실행중인 프로세스가 죽으면 그 프로세스의 파이프에 값을 전달하지 못해 중단된다.

cc -o count count.c

 

#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MSG_SIZE 80
#define PN "./named_pipe_file"

#define PIPE_SIZE 10
#define PIPE_NAME_SIZE 100

int sendData();
int createNumPipe();
int getPipeNo();
int getPipeCnt();

int main(int argc, char *argv[]) {
  char msg[MSG_SIZE];
  int fd, fdn;
  int nread, rc;
  int cnt = 1;
  int pipeNo=0;
  char myPipeNm[PIPE_NAME_SIZE] = {0x00, };

  if (argc == 2) {
    if (!strcmp("daemon", argv[1])) {
      createNumPipe();
      return 0;
    }
  }

  pipeNo = getPipeNo();
  if (pipeNo < 0) return -1;

  sprintf(myPipeNm, "named_pipe_%d", pipeNo);
  printf("my pipe name is %s\n", myPipeNm);
  fflush(stdout);

  if (argc == 2) {
    // 이미 실행중인 경우 중복으로 여러개가 동작함.
    if (!strcmp("start", argv[1])) sendData(pipeNo, cnt);
  }

  /* 기존에 named pipe가 있으면 삭제 */
  if (access(myPipeNm,F_OK) == 0) {
    unlink(myPipeNm);
  }

  /* named pipe 생성하기 */
  if ((rc = mkfifo(myPipeNm,0666)) < 0) {
    printf("fail to make named pipe\n");
    return 0;
  }

  /* named pipe 열기, Read Write가능 해야 한다 */
  if ((fd = open(myPipeNm, O_RDONLY)) < 0) {
    printf("fail to open named pipe:%s\n", myPipeNm);
    return 0;
  }

  while (1) {
    msg[0] = '\0';
    if ((nread = read(fd, msg, sizeof(msg))) < 0 ) {
      printf("fail to call read()\n");
      return 0;
    }
    if (strlen(msg) < 1) continue;

    // 자료 수신후 5초후에 1을 더해서 보낸다.
    printf("received : %s\t", msg);fflush(stdout);
    sleep(5);

    cnt = atoi(msg) + 1;
    sendData(pipeNo, cnt);
  }
  close(fd);


  return 0;
}

// 데이터 보내기
int sendData(int pipeNo, int cnt) {
  char msg[MSG_SIZE];
  int fd;
  int nread, i;
  char otherPipeNm[PIPE_NAME_SIZE] = {0x00, };
  int pipeCnt=0;
  int nextNo=0;

  pipeCnt = getPipeCnt();
  if (pipeCnt < 0) return -1;

  nextNo = (pipeNo + 1) % pipeCnt;
  sprintf(otherPipeNm, "named_pipe_%d", nextNo);

  /* named pipe 열기, Write 전용으로 열기 */
  if ((fd = open(otherPipeNm, O_WRONLY)) < 0) {
    printf("fail to open named pipe:%s\n", otherPipeNm);
    return 0;
  }

  /* Data를 보낸다. */
  snprintf(msg, sizeof(msg), "%d", cnt);
  if ((nread = write(fd, msg, sizeof(msg))) < 0 ) {
    printf("fail to call write()\n");
    return 0;
  }
  printf("send %s to %s\n", msg, otherPipeNm);
  close(fd);

  return 0;

}

/* num pipe 생성하기*/
int createNumPipe() {
  char msg[MSG_SIZE];
  int fd;
  int nread, i, rc;
  int pipeCnt=0;

  /* 기존에 named pipe가 있으면 삭제 */
  if (access(PN, F_OK) == 0) {
    unlink(PN);
  }

  /* named pipe 생성하기 */
  if ((rc = mkfifo(PN,0666)) < 0) {
    printf("fail to make named pipe:%s\n", PN);
    return 0;
  }

  if ((fd = open(PN, O_RDWR)) < 0) {
    printf("fail to open named pipe:%s\n", PN);
    return 0;
  }
  snprintf(msg, sizeof(msg), "%d", pipeCnt);
  if ((nread = write(fd, msg, sizeof(msg))) < 0 ) {
    return 0;
  }

  while(1) {
    // max값을 가져오고 다시 max를 적어준다
    if ((nread = read(fd, msg, sizeof(msg))) < 0 ) {
      printf("fail to call read()\n");
      return -1;
    }
    if ((nread = write(fd, msg, sizeof(msg))) < 0 ) {
      return 0;
    }
    if (strlen(msg) < 1) continue;
    if (pipeCnt == atoi(msg)) continue;
    pipeCnt = atoi(msg);
    printf("%d.", (pipeCnt -1));fflush(stdout);
    sleep(1);
  }
  close(fd);

  return 0;
}

/* pipe no 가져오기*/
int getPipeNo() {
  char msg[MSG_SIZE];
  int fd;
  int nread, i, rc;
  int pipeNo = 0;

  if (access(PN, F_OK) != 0) {
    printf("The pipe not found:%s\n", PN);
    createNumPipe();
  }

  if ((fd = open(PN, O_RDWR)) < 0) {
    printf("fail to open named pipe:%s\n", PN);
    return -1;
  }

  if ((nread = read(fd, msg, sizeof(msg))) < 0 ) {
    printf("fail to call read()\n"); fflush(stdout);
    return -1;
  }
  pipeNo  = atoi(msg);
  snprintf(msg, sizeof(msg), "%d", pipeNo + 1);
  if ((nread = write(fd, msg, sizeof(msg))) < 0 ) {
    printf("write error!\n");
    return 0;
  }
  close(fd);

  return pipeNo;
}

/* pipe 갯수 가져오기*/
int getPipeCnt() {
  char msg[MSG_SIZE];
  int fd;
  int nread, i;
  int pipeCnt = 0;

  if ((fd = open(PN, O_RDWR)) < 0) {
    printf("fail to open named pipe\n");
    return -1;
  }

  // max값을 가져오고 다시 max를 적어준다
  if ((nread = read(fd, msg, sizeof(msg))) < 0 ) {
    printf("fail to call read()\n");
    return -1;
  }
  if ((nread = write(fd, msg, sizeof(msg))) < 0 ) {
    return 0;
  }
  close(fd);

  pipeCnt  = atoi(msg);
  return pipeCnt;
}

Leave a Comment

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

이 사이트는 Akismet을 사용하여 스팸을 줄입니다. 댓글 데이터가 어떻게 처리되는지 알아보세요.