为什么在SunOS上调用msgrcv后得到“E2BIG,但是同样的代码在linux上工作正常?

时间:2012-03-23 12:06:29

标签: c unix

在调用msgrcv()后,我得到了一个E2BIG:在SunOS,CPP编译器上。

输出如下:

arguments:
MsgID: 335006
pointer: 0xffbfbac8
sizeof: 1040
MsgType: 0
MsgFlag: 2048
RetVal=-1
RM: message waiting failed with error 7.

在手册中:

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

Maunal对于msgrcv()说,当“消息文本长度大于msgsz且未在msgflg中指定MSG_NOERROR时”获得E2BIG。

但在我的情况下,看起来长度等于msg文本。顺便说一句,这个函数如何得到void * msgp的长度?这是一个空白。

抱歉,我发布了一段很长的代码,因为我害怕错过一些东西。 感谢。

修改
手册说,

The msgp argument is a pointer to caller-defined structure of the  fol-
       lowing general form:

            struct msgbuf {
                long mtype;       /* message type, must be > 0 */
                char mtext[1];    /* message data */
            };

The  mtext  field is an array (or other structure) whose size is specified by msgsz, a non-negative integer value

我按照以下方式添加gdb的更多信息: 227 RetVal = msgrcv(TDM_M [MyModule] .msg_id, 228(void *)& SysMsg, 229(size_t)sizeof(T_MSGBUF), 230 MsgType, 231 MsgFlag); 23 235 * / (gdb)p sizeof(SysMsg) 10美元= 1044美元 (gdb)p sizeof(T_MSGBUF) $ 11 = 1040

长度 - 目标的大小= 4(=长整数的大小),看起来是正确的。 另外,我发现问题只发生在SunOS上。相同的代码在Linux上运行良好。

编辑我找到了根本原因。就像errno E2BIG指示MsgLength小于收到的消息一样,我的发送宏计数一个错误的值,该值应该等于WAIT_MSG()中的MsgLength。

感谢您的建议和解答。

.h文件 / * MSGBUF是针对特定消息定义的  * SysMsg定义为msgrcv的arg  * /

#define MSGBUF_SIZE     1040
#define MSGBODY_SIZE    (MSGBUF_SIZE)
#define MSGBODY_SIZE1   (MSGBUF_SIZE-16)

typedef struct {

   unsigned char        SrcModule;
   unsigned char        DstModule;
   unsigned char        MsgType;       

   unsigned short       SubMsgId;
   unsigned short       Length;
   long int             reserved;
} MsgHeader;

typedef struct _MsgBody {
   unsigned char Data[MSGBODY_SIZE1];
} MSGBODY;

typedef struct _MsgBuf {
   MsgHeader Header;             // the header of message.
   MSGBODY   Body;                   // the message body.
} MSGBUF;

typedef struct _MsgInside {
    long int        MsgType;
    MSGBUF          MsgText;
} SYS_MSG;

的.cpp

int WaitMsg (DMMODULE        MyModule,
                MSGBUF*       pMsgBuf,
                long            MsgType,
                int             MsgFlag,
                TIME_USEC       abs_timeout)
{
   SYS_MSG      SysMsg;
   int          RetVal;

   ...

    memset(&SysMsg, 0, sizeof(SYS_MSG));


        printf("arguments:\n");
        printf("MsgID: %d\n", Module[MyModule].msg_id);
        printf("pointer: 0x%x\n", (void *)&SysMsg);
        printf("sizeof: %d\n",  (size_t)sizeof(T_MSGBUF));

         printf("MsgType: %d\n", MsgType);
        printf("MsgFlag: %d\n", MsgFlag);

    /* Module is a global array in which msg_id is storing */
    RetVal = msgrcv( Module [MyModule].msg_id,
                     (void *)&SysMsg,
                     (size_t)sizeof(MSGBUF),
                     MsgType,
                     MsgFlag);

    /* So far, only ENOMSG is handled, the rest is ignored,
     * Maybe a signal handler is needed later.
     */
    if( RetVal == -1 )
    {
        switch (errno)
        {
        case ENOMSG:
            return My_ENOMSG;

        case E2BIG:
        case EACCES:
        case EAGAIN:
        case EFAULT:
        case EIDRM:
        case EINTR:
        case EINVAL:

/* Here is where the error reported */

            printf("%s: message waiting failed with error %d.\n",
                     Module[MyModule].name, errno);
            printf("%s: \n", strerror(errno));

            return FAIL;

      default:

            printf("%s: message waiting failed with error %d.\n",
                     Module[MyModule].name, errno);
            printf("%s: \n", strerror(errno));

            return FAIL;
        }
    }

    memcpy(pMsgBuf, &(SysMsg.MsgText), sizeof(T_MSGBUF));


    printf("message is received by %s.\n",  Module[MyModule].name);


    return SUCC;

}

...
#define WAIT_MSG(MyModule,pMsgBuf,time_us )             \
        WaitMsg((MyModule),(pMsgBuf),0,IPC_NOWAIT,0)

int main()
{
   int rc = -1;
   MSGBUF    msgbuf; 

   rc = WAIT_MSG( RM, &msgbuf, 0 );
    ...
}

}

3 个答案:

答案 0 :(得分:1)

错误E2BIG表示您尝试接收的邮件不适合您的缓冲区。你必须让缓冲区更大。你的缓冲区大约是1020或1024字节,我不确定。如果传入的消息较大,则会获得E2BIG

  

顺便说一下,这个函数如何得到void * msgp的长度?这是一个空白。

看起来你对指针的工作原理有点不清楚。指针只指向内存中的单个位置,它们没有长度。 (即使非void指针也没有“长度”。)无论何时指定内存区域,都必须指定其起始位置(void *)及其长度(size_t)。将一系列内存传递给C中的函数时,通常以三种方式之一指定长度:

  1. 长度是固定的。例如,当您调用setjmp时,会将指针传递给内存区域sizeof(jmp_buf)字节长。
  2. 长度作为单独的参数传递。例如,fwritemsgrcv
  3. 使用哨兵发现长度。例如,strlen
  4. <强>建议:

    1. 如果您需要将指针传递为void *,请不要使用强制转换;如果您不小心将非指针强加到void *,这可以隐藏代码中的错误。必要时,指针会自动转换为void *
    2. sizeof的结果始终是size_t,不要施展它。这就像写(int)1(double)0.5(const char [6])"Hello"
    3. 请勿将sizeof(type)用于memcpymsgrcv个参数。 memcpy参数中的错别字是错误的常见来源,并且引用远程类型使得在阅读代码时更难发现它们。

      // Not so good
      // Reading the code, I have to look for the definition of pMsgBuf
      // in order to know if sizeof(T_MSGBUF) is correct
      memcpy(pMsgBuf, &(SysMsg.MsgText), sizeof(T_MSGBUF));
      // Who knows if sizeof(MSGBUF) is correct?
      msgrcv(..., &SysMsg, sizeof(MSGBUF), ...);
      
      // Better
      // Reading the code, I know sizeof(*pMsgBuf) is correct,
      // but &(SysMsg.MsgText) might be a different type.
      memcpy(pMsgBuf, &(SysMsg.MsgText), sizeof(*pMsgBuf));
      msgrcv(..., &SysMsg, sizeof(SysMsg), ...);
      
      // Best
      // Most errors will be caught by the compiler.
      static void msgbuf_copy(MSGBUF *dest, const MSGBUF *src)
      { memcpy(dest, src, sizeof(*dest)); }
      
      msgbuf_copy(pMsgBuf, &SysMsg.MsgText);
      
    4. 如果您希望消息为1024字节,请在代码中写入。不要组装恰好恰好加起来1024字节的结构,使其明确发生。

      typedef struct {
         unsigned char        SrcModule;
         unsigned char        DstModule;
         unsigned char        MsgType;       
      
         unsigned short       SubMsgId;
         unsigned short       Length;
         long int             reserved;
      } MsgHeader;
      
      typedef struct {
         MsgHeader Header;
         char Body[1024 - sizeof(MsgHeader)];
      } MSGBUF;
      

答案 1 :(得分:0)

传递给SysMsg的变量msgrcv的类型为

typedef struct _MsgInside {
    long int        MsgType;
    MSGBUF          MsgText;
} SYS_MSG;

你有没有尝试过愚蠢和简单的事情

typedef struct _MsgInside {
    long int        MsgType;
    char          MsgText[10000];
} SYS_MSG;

看它是否改变了它的行为?

编辑,ooops

此外,字段字段为sizeof(MSGBUF),但邮件的类型为SYS_MSG

充其量这令人困惑;始终使用sizeof(var)

答案 2 :(得分:0)

要计算正确的msgsz,请执行sizeof(SysMsg) - sizeof(SysMsg.MsgType):您必须减去消息缓冲区的long mtype字段。这也必须在发件人中完成。