-
20140624 (레코드 잠금, 파이프 통신, 메시지 큐)부산IT학원/스마트컨트롤러 2014. 6. 24. 14:51
87일차
------------------
레코드 잠금
------------------
--- 파일을 이용해 프로세스간 통신
소스)
exe3.c
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <fcntl.h>
4
5 int main(int argc, char **argv)
6 {
7 int fd;
8 struct flock filelock;
9
10 filelock.l_type = F_WRLCK;
11 filelock.l_whence = SEEK_SET;
12 filelock.l_start = 0;
13 filelock.l_len = 0;
14
15 fd = open(argv[1], O_RDWR | O_CREAT, 0666);
16
17 if(fcntl(fd, F_SETLK, &filelock) == -1)
18 {
19 perror("fcntl failed");
20 exit(1);
21 }
22
23 printf("locked %s\n", argv[1]);
24
25 write(fd, "Hi Linux", 9);
26 sleep(10);
27
28 printf("unlocked %s\n", argv[1]);
29
30 exit(0);
31
32 return 0;
33 }exe4.c
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <fcntl.h>
4
5 #define SIZE 20
6
7 int main(int argc, char **argv)
8 {
9 int fd;
10 struct flock filelock;
11 char buffer[SIZE];
12 int length;
13
14 filelock.l_type = F_RDLCK;
15 filelock.l_whence = SEEK_SET;
16 filelock.l_start = 0;
17 filelock.l_len = 0;
18
19 fd = open(argv[1], O_RDWR);
20
21 if(fcntl(fd, F_SETLKW, &filelock) == -1)
22 {
23 perror("fcntl failed");
24 exit(1);
25 }
26
27 printf("locked %s\n", argv[1]);
28
29 length = read(fd, buffer, SIZE);
30
31 write(STDOUT_FILENO, buffer, length);
32 printf("unlocked %s\n", argv[1]);
33
34 exit(0);
35
36 return 0;
37 }결과
------------------
파이프 통신
------------------
--- 파이프
어떤 통로를 통해 프로세스끼리 통신할 수 있다.
--- popen
파이프를 이용해 명령어를 실행한다.
#include <stdio.h>
FILE *popen(const char *command, const cahr *type);
command : 실행할 명령어
type : 통신 형태
"r" 파이프를 통해 읽음
"w" 파이프를 통해 씀
리턴값
성공시
파일 포인터
실패시
NULL
--- pclose
파이프를 닫는다.
#include <stdio.h>
int pclose(FILE *stream);
stream : 닫을 파이프의 파일 포인터
리턴값
성공시
종료 상태
실패시
-1
--- pipe
파이프를 생성한다.
#include <unistd.h>
int pipe(int filedes[2]);
filedes[0] : 파이프로부터 데이터를 읽을 때 사용하는 파일 식별자
filedes[1] : 파이프에 데이터를 쓸 때 사용하는 파일 식별자
예제 소스)
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <string.h>
4 #include <sys/types.h>
5 #include <sys/wait.h>
6
7 #define SIZE 256
8
9 int main()
10 {
11 int pipes1[2];
12 int pipes2[2];
13 int length;
14 char read_buffer[SIZE];
15 char write_buffer[SIZE];
16
17 if(pipe(pipes1) == -1 || pipe(pipes2) == -1)
18 {
19 perror("pipe failed");
20 exit(1);
21 }
22
23 if(fork())
24 {
25 close(pipes1[1]);
26 close(pipes2[0]);
27
28 if((length = read(pipes1[0], read_buffer, SIZE)) == -1)
18 {
19 perror("pipe failed");
20 exit(1);
21 }
22
23 if(fork())
24 {
25 close(pipes1[1]);
26 close(pipes2[0]);
27
28 if((length = read(pipes1[0], read_buffer, SIZE)) == -1)
29 {
30 perror("read failed");
31 exit(1);
32 }
33
34 write(STDOUT_FILENO, "receive message: ", strlen("receive message: "));
35 write(STDOUT_FILENO, read_buffer, length);
36
37 sprintf(write_buffer, "Hi client!\n");
38 write(pipes2[1], write_buffer, strlen(write_buffer));
39
40 wait(NULL);
41 }
42 else
43 {
44 close(pipes1[0]);
45 close(pipes2[1]);
46
47 sprintf(write_buffer, "Hi server\n");
48 write(pipes1[1], write_buffer, strlen(write_buffer));
49
50 if((length = read(pipes2[0], read_buffer, SIZE)) == -1)
51 {
52 perror("read failed");
53 exit(1);
54 }
55
56 write(STDOUT_FILENO, "receive message: ", strlen("receive message: "));
57 write(STDOUT_FILENO, read_buffer, length);
58 }
59
60 exit(0);
61 return 0;
62 }결과
--- FIFO
파이프는 부모 자식 프로세스 간에만 통신이 가능하고 종료되면 사라져 사용하기에 문제가 있다.
이런 문제점을 해결한 통신 수단이 FIFO이다.
이름있는 파이프라고도 불리는 이놈은 부모 자식간만 아니라 파이프 이름만 알면
어떤 프로세스도 사용가능하고 삭제하지 않는한 영구적이다.
--- mkfifo
FIFO를 생성한다.
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char * pathname, mode_t mode);
pathname : 생성될 FIFO의 이름
mode : 생성될 FIFO의 접근 권한
리턴값
성공시
0
실패시
-1
예제 소스)
25_13.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <fcntl.h>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6
7 #define SIZE 128
8 #define FIFO "fifo"
9
10 int main(int argc, char **argv)
11 {
12 int fd;
13 char buffer[SIZE];
14
15 if(mkfifo(FIFO, 0666) == -1)
16 {
17 perror("mkdifo failed");
18 exit(1);
19 }
20
21 if((fd = open(FIFO, O_RDWR)) == -1)
22 {
23 perror("open failed");
24 exit(1);
25 }
26
27 while(1)
28 {
29 if(read(fd, buffer, SIZE) == -1)
30 {
31 perror("read failed");
32 exit(1);
33 }
34
35 if(!strcmp(buffer, "quit"))
36 {
37 exit(0);
38 }
39
40 printf("receive messgae: %s\n", buffer);
41 }
42
43 return 0;
44 }25_14.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <fcntl.h>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6
7 #define SIZE 128
8 #define FIFO "fifo"
9
10 int main(int argc, char ** argv)
11 {
12 int fd;
13 int i;
14 char buffer[SIZE];
15
16 if((fd = open(FIFO, O_WRONLY)) == -1)
17 {
18 perror("open failed");
19 exit(1);
20 }
21
22 for(i = 1; i < argc; ++i)
23 {
24 strcpy(buffer, argv[i]);
25
26 if(write(fd, buffer, SIZE) == -1)
27 {
28 perror("write failed");
29 exit(1);
30 }
31 }
32
33 return 0;
34 }결과
그런데 결과 그림에서는 잘 나온것 처럼 보이지만
사실 생성 권한? 이 없다는 오류가 났었는데 작업하던 디렉토리가
윈도우쪽 폴더라 에러가 났었다.
-------------
메시지 큐
-------------
--- msgget
메시지 큐를 생성한다.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
key : 시스템에서 식별하는 메시지 큐 번호
msgflg : 동작 옵션
IPC_CREAT : key에 해당하는 메시지 큐가 없으면 큐를 새로 생성하는데,
이 때 접근 권한도 함께 부여해야 한다. 그러나 큐가 없으면 이 옵션은 무시한다.
큐가 있다면 식별자를 리턴값으로 준다.
IPC_EXCL : 메시지 큐가 있으면 실패라는 의미로 -1을 반환한다. 이 값이 설정되지 않으면
기존 메시지 큐에 접근해 식별자를 리턴한다.
리턴값
성공시
메시지 큐 식별자
실패시
-1
--- msgsnd
메시지 큐에 메시지를 전송한다.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, struct msgbuf * msgp, size_t msgsz, int msgflg);
msqid: 메시지 큐 식별자
msgp : 전송할 메시지
mssbuf 라고 기본적인 데이터형
struct msgbuf
{
long mtype;
char mtext[1];
};
크기가 매우 작지만 사용자 임의로 새로 만들수 있다
struct 데이터명
{
long type; // 첫 변수만 항상 long 형으로 지켜줘야한다.
아무타입...
};
msgsz : 메시지 크기
msgflg : 동작 옵션
IPC_NOWAIT : 메시지 큐가 가득 차 있어 메시지를 더 이상 저장할 수없을 경우에 실패로 -1 반환한다.
이 값을 설정하지 않으면 메시지 큐가 메시지를 저장할 수 있을 때까지 기다린다.
리턴값
성공시
0
실패시
-1
--- msgrcv
메시지 큐에 있는 메시지를 수신한다.
#include <sys/types.h>
#include <sys/ipc.h>
#include <msg.h>
ssize_t msgrcv(int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg);
msqid : 메시지 큐 식별자
msgp : 메시지 수신할 곳
msgsz : 수신 가능한 메시지 크기
msgtyp : 수신할 메시지 선택 조건
0 : 메시지 큐에서 첫 번째 메시지를 수신한다.
양수 : 이 값과 메시지의 메시지 형식(mtype)이 일치하는 메시지를 수신한다.
음수 : 이 값의 절대값과 같거나 작은 메시지 형식을 갖는 메시지 중에서 가장 작은 메시지
형식을 갖는 메시지를 수신한다. 예를 들어, 세 개의 메시지 형식이 각각 5, 1, 9라 하자.
msgtyp가 -10이라면 -10의 절대값인 10보다 작거나 같은 메시지 형식을 갖는 메시지는
모두 해당된다. 이 중 가장 작은 1을 메시지 형식으로 갖고 있는 메시지를 수신한다.
msgflg : 동작 옵션
IPC_NOWAIT : 메시지 큐에 메시지가 없으면 실패로 -1을 반환한다. 이 값을 설정하지 않으면
메시지가 메시지 큐에 도착할 때까지 기다린다.
MSG_NOERROR : 메시지 크기가 msgsz보다 클 때 초과되는 부분을 자른다. 이 값을 설정
하지 않으면 실패로 -1을 반환한다.
리턴값
성공시
수신한 메시지 크기
실패시
-1
--- msgctl
메시지 큐를 제어한다.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
msqid : 메시지 큐 식별자
cmd : 제어 종류
buf : 메시지 큐 정보에 대한 포인터
리턴값
성공시
0
실패시
-1
예제 소스)
msg1.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <sys/types.h>
4 #include <sys/ipc.h>
5 #include <sys/msg.h>
6 #include <signal.h>
7
8 #define SIZE 124
9
10 void signalHandler(int signo);
11
12 //메시지를 저장하는 데이터형으로 첫 번재 멤버는 메시지 형식이어야 함
13 struct{
14 long type;
15 char data[SIZE];
16 }msg_data={1, "Linux C Programming"};
17
18 int msqid;
19
20 int main()
21 {
22 //1234 키를 갖는 메시지 큐를 생성하고 메시지 큐 식별자인 정수값을 반환
23 //만약 1234 키의 메시지 큐가 있으면 메시지 큐에 접근하여 식별자를 반환
24 if(msqid=msgget((key_t)1234, IPC_CREAT|0666) == -1)
25 {
26 perror("msgget failed");
27 exit(1);
28 }
29
30 //msg_data 메시지를 msqid 메시지 큐에 전송
31 if(msgsnd(msqid, &msg_data, strlen(msg_data.data),0) == -1)
32 {
33 perror("msgsnd failed");
34 exit(1);
35 }
36
37 //SIGINT 시그널을 받으면 signalHandler을 실행하도록 설정
38 signal(SIGINT,signalHandler);
39 pause();
40
41 return 0;
42 }
43
44 void signalHandler(int signo)
45 {
46 //msqid 메시지 큐 삭제
47 if(msgctl(msqid,IPC_RMID,0)== -1)
48 {
49 perror("msgctl failed");
50 exit(1);
51 }
52
53 exit(0);
54 }msg2.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <sys/types.h>
4 #include <sys/ipc.h>
5 #include <sys/msg.h>
6 #include <signal.h>
7
8 #define SIZE 124
9
10 struct
11 {
12 long type;
13 char data[SIZE];
14 }msg_data;
15
16 int main()
17 {
18 int msqid;
19 struct msqid_ds msg_stat;
20
21 //1234 키의 메시지 큐가 있으면 접근해서 식별자 받음
22 if(msqid=msgget((key_t)1234,IPC_CREAT|0666) == -1)
23 {
24 perror("msgget failed");
25 exit(1);
26 }
27
28 //msqid 메시지 큐에서 메시지를 읽어 msg_data에 저장
29 if(msgrcv(msqid, &msg_data, SIZE,0,0) == -1)
30 {
31 perror("msgrcv failed");
32 exit(1);
33 }
34
35 printf("data read from message queue : %s\n",msg_data.data);
36
37 //msqid 메시지 큐 정보를 얻어 msg_stat에 저장
38 if(msgctl(msqid, IPC_STAT, &msg_stat) == -1)
39 {
40 perror("msgctl failed");
41 exit(1);
42 }
43
44 //msg_stat.msg_lspid 프로세스에게 SIGINT 시그널을 보냄
45 kill(msg_stat.msg_lspid,SIGINT);
46
47 exit(0);
48
49 return 0;
50 }실행
'부산IT학원 > 스마트컨트롤러' 카테고리의 다른 글
20140626 (select, 1:1 채팅) (0) 2014.06.26 20140625 (메시지 큐 우선순위, 공유 메모리) (0) 2014.06.25 20140623 (pthread, 레코드 잠금) (0) 2014.06.23 20140620 (시그널, 멀티쓰레드) (0) 2014.06.20 20140619 (프로세스, 함수 포인터) (0) 2014.06.19