Chinaunix首页 | 论坛 | 博客
  • 博客访问: 175926
  • 博文数量: 52
  • 博客积分: 770
  • 博客等级: 军士长
  • 技术积分: 439
  • 用 户 组: 普通用户
  • 注册时间: 2010-11-10 11:34
文章分类

全部博文(52)

文章存档

2014年(11)

2013年(21)

2012年(4)

2011年(8)

2010年(8)

我的朋友

分类:

2010-12-30 14:50:07

今天写了一个小程序,使用了消息队列的msgsnd msgrcv函数,由msgsnd函数循环处理由终端输入的消息,然后把它发送到消息队列,而另一个进程则循环读取消息,进行处理。
    这时,问题出现了,每次调用msgrcv函数的时候,它总是第一次调用成功,而第二次返回错误,察看errno=22,打印出来是invalid argument,无效参数。
    凭它的说明,可以看出可能是我调用函数的时候参数错误,但为什么第一次能调用成功呢?
    检查了一下,没看出问题。然后google之,发现许多人和我出现了同样的问题,但没有人给出解答。
    自己鼓捣了好久,还是没搞定。
    然后man 2 msgsnd,一下午不知打了多少遍了,这一次从头到尾一个字一个字的读了下去。
    终于发现问题了。
       int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

        ssize_t msgrcv(
int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
    man文档里有一句话:The mtext field is an array (or other structure) whose size is specified by msgsz  
    一直没认真去看,想当然的以为msgsz就是msgp的大小了,原来人家不是,自己自作多情了。。。

    这么一个小问题花了我半个下午,但现在发现总比以后出错要好多了~
    写出来,给那些第一次使用的朋友们看~~
   
    把修改后的代码贴出来:

struct s_msg{
    
long type;
    
char mtext[256];
};

//snd
int
main()
{
    
int mid;
    
if((mid=msgget(4446,IPC_CREAT|0666))==-1)
         perr_exit(
"msgget:");
    
char buf[BUFSIZE];
     memset(buf,
'\0',BUFSIZE);
     s_msg mymsg;
    
while(fgets(buf,BUFSIZE,stdin)!=NULL){
        
if(strlen(buf)<=2)continue;
         buf[strlen(buf)]
='\0';
        
if(sscanf(buf,"%d%s",&mymsg.type,mymsg.mtext)!=2)
             perr_exit(
"Invalid input:");
        
if(msgsnd(mid,&mymsg,256,IPC_NOWAIT))      //msgsiz 为sizeof(mtext[]),而非sizeof(s_msg)
             perr_exit(
"msgsnd:");
         memset(buf,
'\0',BUFSIZE);
     }
    
return 0;
}
//rcv
int
main(int argc,char **argv)
{
    
int mid;
    
if((mid=msgget(4446,IPC_CREAT|0666))==-1)
         perr_exit(
"msgget:");
     s_msg mymsg;
    
while(1)
     {
        
if(msgrcv(mid,&mymsg,256,0,MSG_NOERROR)==-1)   //就是这里出错的,记住你了
                 perr_exit(
"msgrcv");
        
if(mymsg.type!=4446)
             cout
<<mymsg.type<<" :"<<mymsg.mtext<<endl;
        
else {
             cout
<<"4446 quit\n";
            
break;    
         }
         memset(
&mymsg,0,sizeof(mymsg));
     }
    
return 0;
}

/*********************************msgsnd 详解**************************************/

NAME

msgsnd - XSI message send operation

SYNOPSIS

[XSI] [Option Start] #include <sys/msg.h>

int msgsnd(int
msqid, const void *msgp, size_t msgsz, int msgflg); [Option End]

DESCRIPTION

The msgsnd() function operates on XSI message queues (see the Base Definitions volume of IEEE Std 1003.1-2001, Section 3.224, Message Queue). It is unspecified whether this function interoperates with the realtime interprocess communication facilities defined in Realtime.

The msgsnd() function shall send a message to the queue associated with the message queue identifier specified by msqid.

The application shall ensure that the argument msgp points to a user-defined buffer that contains first a field of type long specifying the type of the message, and then a data portion that holds the data bytes of the message. The structure below is an example of what this user-defined buffer might look like:

struct mymsg {
long mtype; /* Message type. */
char mtext[1]; /* Message text. */
}

The structure member mtype is a non-zero positive type long that can be used by the receiving process for message selection.

The structure member mtext is any text of length msgsz bytes. The argument msgsz can range from 0 to a system-imposed maximum.

The argument msgflg specifies the action to be taken if one or more of the following is true:

  • The number of bytes already on the queue is equal to msg_qbytes; see .

  • The total number of messages on all queues system-wide is equal to the system-imposed limit.

These actions are as follows:

  • If (msgflg & IPC_NOWAIT) is non-zero, the message shall not be sent and the calling thread shall return immediately.

  • If (msgflg & IPC_NOWAIT) is 0, the calling thread shall suspend execution until one of the following occurs:

    • The condition responsible for the suspension no longer exists, in which case the message is sent.

    • The message queue identifier msqid is removed from the system; when this occurs, errno shall be set equal to [EIDRM] and -1 shall be returned.

    • The calling thread receives a signal that is to be caught; in this case the message is not sent and the calling thread resumes execution in the manner prescribed in sigaction().

Upon successful completion, the following actions are taken with respect to the data structure associated with msqid; see :

  • msg_qnum shall be incremented by 1.

  • msg_lspid shall be set equal to the process ID of the calling process.

  • msg_stime shall be set equal to the current time.

RETURN VALUE

Upon successful completion, msgsnd() shall return 0; otherwise, no message shall be sent, msgsnd() shall return -1, and errno shall be set to indicate the error.

ERRORS

The msgsnd() function shall fail if:

[EACCES]
Operation permission is denied to the calling process; see XSI Interprocess Communication.
[EAGAIN]
The message cannot be sent for one of the reasons cited above and (msgflg & IPC_NOWAIT) is non-zero.
[EIDRM]
The message queue identifier msqid is removed from the system.
[EINTR]
The msgsnd() function was interrupted by a signal.
[EINVAL]
The value of msqid is not a valid message queue identifier, or the value of mtype is less than 1; or the value of msgsz is less than 0 or greater than the system-imposed limit.

The following sections are informative.

EXAMPLES

Sending a Message

The following example sends a message to the queue identified by the msqid argument (assuming that value has previously been set). This call specifies that an error should be reported if no message is available. The message size is calculated directly using the sizeof operator.

#include 
...
int result;
int msqid;
struct message {
long type;
char text[20];
} msg;


msg.type = 1;
strcpy(msg.text, "This is message 1");
...
result = msgsnd(msqid, (void *) &msg, sizeof(msg.text), IPC_NOWAIT);

APPLICATION USAGE

The POSIX Realtime Extension defines alternative interfaces for interprocess communication (IPC). Application developers who need to use IPC should design their applications so that modules using the IPC routines described in XSI Interprocess Communication can be easily modified to use the alternative interfaces.

RATIONALE

None.

FUTURE DIRECTIONS

None.

SEE ALSO

XSI Interprocess Communication, Realtime, mq_close(), mq_getattr(), mq_notify(), mq_open(), mq_receive(), mq_send(), mq_setattr(), mq_unlink(), msgctl(), msgget(), msgrcv(), sigaction(), the Base Definitions volume of IEEE Std 1003.1-2001,

CHANGE HISTORY

First released in Issue 2. Derived from Issue 2 of the SVID.

Issue 5

The note about use of POSIX Realtime Extension IPC routines has been moved from FUTURE DIRECTIONS to a new APPLICATION USAGE section.

Issue 6

The DESCRIPTION is updated to avoid use of the term "must" for application requirements.


/***********************************************msgrcv***************************************************/

NAME

msgrcv - XSI message receive operation

SYNOPSIS

[XSI] [Option Start] #include <sys/msg.h>

ssize_t msgrcv(int
msqid, void *msgp, size_t msgsz, long msgtyp,
       int
msgflg); [Option End]

DESCRIPTION

The msgrcv() function operates on XSI message queues (see the Base Definitions volume of IEEE Std 1003.1-2001, Section 3.224, Message Queue). It is unspecified whether this function interoperates with the realtime interprocess communication facilities defined in Realtime.

The msgrcv() function shall read a message from the queue associated with the message queue identifier specified by msqid and place it in the user-defined buffer pointed to by msgp.

The application shall ensure that the argument msgp points to a user-defined buffer that contains first a field of type long specifying the type of the message, and then a data portion that holds the data bytes of the message. The structure below is an example of what this user-defined buffer might look like:

struct mymsg {
long mtype; /* Message type. */
char mtext[1]; /* Message text. */
}

The structure member mtype is the received message's type as specified by the sending process.

The structure member mtext is the text of the message.

The argument msgsz specifies the size in bytes of mtext. The received message shall be truncated to msgsz bytes if it is larger than msgsz and (msgflg & MSG_NOERROR) is non-zero. The truncated part of the message shall be lost and no indication of the truncation shall be given to the calling process.

If the value of msgsz is greater than {SSIZE_MAX}, the result is implementation-defined.

The argument msgtyp specifies the type of message requested as follows:

  • If msgtyp is 0, the first message on the queue shall be received.

  • If msgtyp is greater than 0, the first message of type msgtyp shall be received.

  • If msgtyp is less than 0, the first message of the lowest type that is less than or equal to the absolute value of msgtyp shall be received.

The argument msgflg specifies the action to be taken if a message of the desired type is not on the queue. These are as follows:

  • If (msgflg & IPC_NOWAIT) is non-zero, the calling thread shall return immediately with a return value of -1 and errno set to [ENOMSG].

  • If (msgflg & IPC_NOWAIT) is 0, the calling thread shall suspend execution until one of the following occurs:

    • A message of the desired type is placed on the queue.

    • The message queue identifier msqid is removed from the system; when this occurs, errno shall be set equal to [EIDRM] and -1 shall be returned.

    • The calling thread receives a signal that is to be caught; in this case a message is not received and the calling thread resumes execution in the manner prescribed in sigaction().

Upon successful completion, the following actions are taken with respect to the data structure associated with msqid:

  • msg_qnum shall be decremented by 1.

  • msg_lrpid shall be set equal to the process ID of the calling process.

  • msg_rtime shall be set equal to the current time.

RETURN VALUE

Upon successful completion, msgrcv() shall return a value equal to the number of bytes actually placed into the buffer mtext. Otherwise, no message shall be received, msgrcv() shall return (ssize_t)-1, and errno shall be set to indicate the error.

ERRORS

The msgrcv() function shall fail if:

[E2BIG]
The value of mtext is greater than msgsz and (msgflg & MSG_NOERROR) is 0.
[EACCES]
Operation permission is denied to the calling process; see XSI Interprocess Communication.
[EIDRM]
The message queue identifier msqid is removed from the system.
[EINTR]
The msgrcv() function was interrupted by a signal.
[EINVAL]
msqid is not a valid message queue identifier.
[ENOMSG]
The queue does not contain a message of the desired type and (msgflg & IPC_NOWAIT) is non-zero.

The following sections are informative.

EXAMPLES

Receiving a Message

The following example receives the first message on the queue (based on the value of the msgtyp argument, 0). The queue is identified by the msqid argument (assuming that the value has previously been set). This call specifies that an error should be reported if no message is available, but not if the message is too large. The message size is calculated directly using the sizeof operator.

#include 
...
int result;
int msqid;
struct message {
long type;
char text[20];
} msg;
long msgtyp = 0;
...
result = msgrcv(msqid, (void *) &msg, sizeof(msg.text),
msgtyp, MSG_NOERROR | IPC_NOWAIT);

APPLICATION USAGE

The POSIX Realtime Extension defines alternative interfaces for interprocess communication (IPC). Application developers who need to use IPC should design their applications so that modules using the IPC routines described in XSI Interprocess Communication can be easily modified to use the alternative interfaces.

RATIONALE

None.

FUTURE DIRECTIONS

None.

SEE ALSO

XSI Interprocess Communication, Realtime, mq_close(), mq_getattr(), mq_notify(), mq_open(), mq_receive(), mq_send(), mq_setattr(), mq_unlink(), msgctl(), msgget(), msgsnd(), sigaction(), the Base Definitions volume of IEEE Std 1003.1-2001,

CHANGE HISTORY

First released in Issue 2. Derived from Issue 2 of the SVID.

Issue 5

The type of the return value is changed from int to ssize_t, and a warning is added to the DESCRIPTION about values of msgsz larger the {SSIZE_MAX}.

The note about use of POSIX Realtime Extension IPC routines has been moved from FUTURE DIRECTIONS to the APPLICATION USAGE section.

Issue 6

The DESCRIPTION is updated to avoid use of the term "must" for application requirements.



/**************************************************************************************************/
消息队列部分
消息队列
消息队列可以认为是一个消息链表。有足够写权限的线程就可往队列中放置消息,有足够读权限的线程就可以从队列中取走消息。每个消息是一个记录,他有发送者赋予一个优先级。在某个进程往一个队列写入消息之前,并不需要另外某个进程在该队列上等待消息的到达。
Posix消息队列和System V系统的消息队列区别:
1、 对Posix消息队列的读总是返回最高优先级的最早消息,对System V消息队列得读则可以返回任意指定优先级的消息
2、 当往一个队列放置一个消息时,Posix消息队列允许产生一个信号或启动一个线程,System V消息队列则不提供类似的机制
消息的属性:
1、 一个无符号整数优先级(Posix)或是长整类型(SystemV)
2、 消息的数据部分长度
3、 数据本身
(System V系统发送消息时需要定义消息的结构,而Posix系统不需要定义这样的结构)
Posxi 消息队列
mq_open   创建一个新消息队列或是打开一个已经存在的消息队列,返回值成为消息队列描述字。
mq_close   关闭已打开的消息队列。
mq_unlink   从系统删除消息队列。
每个消息队列有四个属性,有mq_getattr获得这些属性,mq_setattr设置其中某个属性
   mq_send:用于往一个队列中放置一个消息
   mq_receive:用于往一个队列中取走一个消息,该函数总是返回所指定队列中最高优先级的最早的消息,而且该优先级能随该消息的内容及长度一同返回。
每个消息有一个优先级,他是一个小于MQ_PRIO_MAX的无符号整数,Posix要求这个上限至少为32 。
mq_notify 该函数给指定队列建立或删除异步事件通知
int mq_notify(mqd_t mqdes ,const struct sigevent *notification);
使用规则:
1、 如果notification参数非空,那么当前进程希望在有一个消息到达所指定队列而且该队列先前为空时得到通知。我们说该进程被注册为接收该队列的通知
2、 如果notification参数为空指针,而且当前进程目前被注册为接收所指定队列的通知,那么现有注册将被撤销。
3、 任意时刻只有一个进程可以被注册为接收某个给定队列的通知。
4、 当有一个消息到达某个先前为空的队列,而且已有一个进程被注册为接收该队列的通知时,只有没有任何进程阻赛在该队列的mq_receive调用的前提下,通知才会发生。这就是说,在mq_revcive调用中的阻赛比任何通知的注册都优先。
5、 当该通知被发送给他的注册进程时,其注册即被撤销,该进程必须再次调用该函数以重新注册。
(当消息队列有消息来到时该函数产生一个信号或时线程,信号或线程是由struct sigevent 参数指定的)
System V 的消息队列
   System V消息队列使用消息队列标示符标示。具有足够特权的任何进程都可以往一个队列放置一个消息,具有足够特权的任何进程都可以从一个给定队列读出一个消息。
对于系统中的每个消息队列,内核维护一个信息结构,struct msqid_ds
msgget函数用于创建一个新的消息队列或访问一个已经存在的消息队列msgget(key_t key ,int oflag ),在创健一个新消息队列时,msqid_ds结构将被初始化。
msgsnd函数往msgget函数建立的消息队列中放置一个消息,
msgsnd(int msqid,const void * ptr,size_t length,int flag);其中ptr是一个结构指针,该结构具有如下的模板struct msgbuf{long mtype ; char mtext[1]}; 该模板可以在;中找到
其中消息类型必须大于0,msgbuf 结构定义中的名字mtext不大确切;消息的数据部分并不局限于文本,任何形式的数据都是允许的,无论是二进制数据还是文本。内核根本不解释消息数据的内容。使用模板的说法描述这个结构,因为ptr所指向的只是一个含有消息类型的长整数,消息本身则紧跟在他之后。不过大多数应用并不使用msgbuf结构的这个定义,因为其数据量通常是不够的。大多数应用定义自己的消息结构,其数据部分根据应用的需要定义。例如:应用需要交换由一个16位整数后跟一个8字节字符数组构成的消息,那么它的结构如下:typedef struct my_msgbuf{ long mytype ; int16_t mshort; char mchar[8];}
msgsnd 的length参数以字节为单位指定代发送消息的长度。这是位于长整数消息类型之后的用户自定义数据的长度。该长度可以是0。如上例长度为 sizeof(struct my_msgbuf)-sizeof(long).
msgrcv(int msqid,void *ptr ,size_t length,long type ,int flag)函数中ptr参数指定所接受消息的存放位置。和msgsnd一样,该指针指向紧挨在真正的消息数据之前返回的长整数类型字段(就是定义的消息结构体)。Length指定由ptr指向的缓冲区中数据部分的大小。这是该函数能返回的最大数据量。该长度不包括长整数类型字段。Type指定希望从所给定的队列中读出什么样的消息:
如果type为0,那就返回该队列中的第一个消息。
如果type大于0,那就返回其类型值为type的第一个消息。
如果type小于0,那就返回其类型值小于或等于type参数的绝对值的消息中类型值得最小的第一个消息。
Msgrcv的flag参数指定所请求类型的消息不在所指定的队列中时怎么办。成功返回时,msgrcv返回所接收消息中数据的字节数。他不包括也通过ptr参数返回的长整数消息类型所需的几个字节。
Msgctl函数提供在一个消息队列上的各种控制操作。Msgctl(int msqid ,int cmd ,struct msqid_de *buff);
三个命令:IPC_RMID 从系统删除指定的消息队列;
IPC_SET 给所指定的消息队列设置其msqid_ds结构的成员;
IPC_STAT 给调用者返回对应所指定消息队列的当前msqid_ds结构
阅读(14776) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2011-01-04 09:03:04

很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com