다음 위로 이전 목차 리눅스 프로그래머를 위한 가이드

시스템 호출:msgsnd() (SYSTEM CALL:msgsnd())

큐의 확인자를 가지고 있으면, 큐 상에서 여러가지 동작을 수행할 수 있다. 큐에 메세지를 전달하기 위해 msgsnd 시스템 호출을 사용한다.:


SYSTEM CALL: msgsnd();                                                          

  PROTOTYPE: int msgsnd ( int msqid, struct msgbuf *msgp, int msgsz, int msgflg );
    RETURNS: 0 on success
             -1 on error: errno = EAGAIN (queue is full, and IPC_NOWAIT was asserted)
                                  EACCES (permission denied, no write permission)
                                  EFAULT (msgp address isn't accessable - invalid)
                                  EIDRM  (The message queue has been removed)
                                  EINTR  (Received a signal while waiting to write)
                                  EINVAL (Invalid message queue identifier, nonpositive
                                          message type, or invalid message size) 
                                  ENOMEM (Not enough memory to copy message buffer)
  NOTES:

msgsnd의 첫번째 아규먼트는 이전의 msgget 호출에 의해 반환된 큐 확인자이다. 두번째 아규먼트인 msgp는 재선언되고 적재된 메세지 버퍼의 포인터이다. msgsz 아규먼트는 메세지 타입의 길이(4바이트)를 제외한 메세지의 바이트 크기를 포함한다.

msgflg 아규먼트는 0으로 지정될 수 있다.(ignored), or:

IPC_NOWAIT

메세지 큐가 가득 찼으면, 메세지는 큐에 씌여질 수 없고, 통제권(control)은 호출한 프로세스에게 돌아간다. 지정되지 않았으면, 호출한 프로세스는 메세지가 씌여질 수 있을 때까지 기다릴 것이다.
메세지를 보내는 또 다른 wrapper 함수를 만들어보자:


int send_message( int qid, struct mymsgbuf *qbuf )
{
	int	result, length;

	/* 길이는 기본적으로 구조체의 크기 - mtype의 크기 이다. */
	length = sizeof(struct mymsgbuf) - sizeof(long);

	if((result = msgsnd( qid, qbuf, length, 0)) == -1)
	{
		return(-1);
	}

	return(result);
}

이 작은 함수는 넘겨진 큐 확인자(qid)에 의해 고안된 메세지 큐에 넘겨진 주소(qbuf)에 있는 메세지를 보내려고 한다. 여기 우리가 지금까지 개발한 두개의 wrapper 함수를 활용한 간단한 코드가 있다.:


#include <stdio.h>
#include <stdlib.h>
#include <linux/ipc.h>
#include <linux/msg.h>

main()
{
	int	qid;
	key_t	msgkey;
	struct	mymsgbuf {
		long	mtype;		/* 메세지 타입 */
		int	request;	/* 작업 요청 번호 */
		double	salary;		/* 직원의 급여 */
	} msg;

	/* IPC 키 값을 발생시킨다 */
	if(( qid = open_queue( mdgkey)) == -1) {
		perror("open_queue");
		exit(1);
	}

	/* 임의의 테스트 자료를 메세지에 적재한다 */
	msg.mtype   = 1;	/* 메세지 타입은 양수여야 한다 */
	msg.request = 1;	/* 자료 요소 #1 */
	msg.salary  = 1000.00;	/* 자료 요소 #2 (나의 연간 급여) */

	/* 뻥 날려보낸다 */
	if((send_message( qid, &msg )) == -1) {
		perror("send_message");
		exit(1);
	}
}

메세지 큐를 만들고 연 후에, 메세지 버퍼에 테스트용 자료를 적재하는데 까지 했다. (이진 정보를 보내는 것에 대한 우리의 관점을 설명하기에는 문자 자료가 부족했음을 주목하라) 빠른 send_message의 호출은 단순히 메세지를 메세지 큐로 분배한다.

현재 우리는 큐에 메세지를 가지고 있으며, 큐의 상태를 보기위해 ipcs 명령어를 사용해라. 큐로 부터 실제로 메세지를 조회하기 위한 토론에 들어가 보자. 그런 일을 하기위해 msgrcv() 시스템 호출을 사용한다.:


  SYSTEM CALL: msgrcv();                                                          
  PROTOTYPE: int msgrcv ( int msqid, struct msgbuf *msgp, int msgsz, long mtype, int msgflg );
    RETURNS: Number of bytes copied into message buffer
             -1 on error: errno = E2BIG  (Message length is greater than msgsz, no MSG_NOERROR)
                                  EACCES (No read permission)
                                  EFAULT (Address pointed to by msgp is invalid)
                                  EIDRM  (Queue was removed during retrieval)
                                  EINTR  (Interrupted by arriving signal)
                                  EINVAL (msgqid invalid, or msgsz less than 0)
                                  ENOMSG (IPC_NOWAIT asserted, and no message exists
                                          in the queue to satisfy the request) 
  NOTES:

명백하게, 첫번째 아규먼트는 메세지 조회 처리를 하는 동안 사용될 큐를 지정하는데 사용된다. (일찍이 msgget를 호출하여 반환된 것이여야 함) 두번째 아규먼트(msgp)는 조회된 메세지를 저장할 메세지 버퍼 변수의 주소를 나타낸다. 세번째 아규먼트(msgsz)는 mtype 멤버의 길이를 제외한 메세지 버퍼 구조체의 크기를 나타낸다. 다시 한번 다음처럼 쉽게 계산될 수 있다.:


msgsz = sizeof(struct mymsgbif) - sizeof(long);


네번째 아규먼트(mtype)는 큐로 부터 조회될 메세지의 타입을 지정한다. 커널은 타입과 매칭되는 가장 오래된 메세지를 큐에서 찾을 것이고 msgp 아규먼트에 의해 지적된 주소에 그것을 복사하여 반환할 것이다. 한가지 특별한 경우가 존재한다. mtype 아규먼트에 0 값이 넘어오면, 타입을 무시하고 큐에서 가장 오래된 메세지를 반환한다.

IPC_NOWAIT가 flag처럼 넘겨지고 이용가능한 메세지가 없으면, 호출한 프로세스에게 ENOMSG를 반환한다. 그렇지 않으면, 호출한 프로세스는 msgrcv() 파리미터를 만족시키는 메세지가 큐에 도착할 때까지 기다린다. 클라이언트가 메세지를 기다리고 있는 동안 큐가 지워지면, EIDRM이 반환된다. 프로세스가 차단 상태에 있거나 메세지가 도착하기를 기다리는 동안 신호가 잡히면, EINTR가 반환된다.

큐로 부터 메세지를 조회하는 빠른 wrapper 함수를 점검해 보자.:


int read_message( int qid, long type, struct mymsgbuf *qbuf )
{
        int     result, length;

	/* 크기는 기본적으로 구조체의 크기 - mtype의 크기 이다. */
        length = sizeof(struct mymsgbuf) - sizeof(long);        

        if((result = msgrcv( qid, qbuf, length, type,  0)) == -1)
        {
                return(-1);
        }
        
        return(result);
}
큐로 부터 메세지의 조회가 성공적으로 이루어지면, 큐 안에 있는 메세지는 파괴된다.

msgflg 아규먼트 안의 MSG_NOERROR 비트는 몇몇의 부가적인 능력을 제공한다. 물리적인 메세지 자료의 크기가 msgsz보다 크고 MSG_NOERROR가 사용되면, 메세지는 잘려져 오직 msgsz 바이트만큼만 반환된다. 일반적으로 msgrcv() 시스템 호출은 -1(E2BIG)을 반환하고 다음의 조회를 위해 큐 상에 메세지를 남겨 놓는다. 이런 동작은 우리의 요청에 만족하는 메세지가 도착했는지를 알아보기 위해 우리가 큐 안을 엿볼(peek) 수 있는 또 다른 wrapper 함수를 만들어 사용할 수 있다.


int peek_message( int qid, long type )
{
        int     result, length;

        if((result = msgrcv( qid, NULL, 0, type,  IPC_NOWAIT)) == -1)
        {
                if(errno == E2BIG)
                        return(TRUE);
        }
        
        return(FALSE);
}

위에서 당신은 버퍼의 주소와 길이가 부족함을 알 것이다. 이런 특별한 경우에 있어서, 우리는 호출이 실패하기를 원한다. 그렇지만 우리는 우리가 요청한 타입과 일치되는 메세지가 존재하는지를 나타내는 E2BIG의 반환을 확인한다. wrapper 함수는 성공하면 TRUE를, 그렇지않으면 FALSE를 반환한다. 또한 이전에 언급했던 차단 동작(Blocking behavior)을 막기위한 IPC_NOWAIT flag의 사용에 주목하라.


이전:시스템 호출:msgget() (SYSTEM CALL:msgget()) 다음:시스템 호출:msgctl() (SYSTEM CALL:msgctl())

Copyright (c) 1996,1997 by Euibeom.Hwang & SangEun.Oh All Rights Reserved

Email To:Webmaster , Another address
LAST UPDATE Nov 18,1997
Created Nov 17,1997