最近在搞进程间通信,首先在我的ubuntu 14.04上写了接口和测试demo,编译和执行都OK,,代码如下:

接口文件ipcmsg.h

/*
ipcmsg.h */
#ifndef H_MSGIPC_H
#define H_MSGIPC_H

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <ipcmsg.h>

#define     MSGKEY            666
#define BUF_SIZE 64
#define APP_PARA_LEN 16 #ifdef __cplusplus
extern "C"{
#endif typedef enum ipc_msg_type
{
APP_MSG,
INPUT_MSG,
GPS_MSG
}ipc_type_t ; typedef struct msgIpc
{
ipc_type_t type;
char buf[BUF_SIZE];
}ipc_msg_t; typedef enum app_cmd {
//RECORD CMDS
START_RECORD = 1001,
STOP_RECORD,
GET_RECORD_TIME,
SWITCH_CAMERA,
TAKE_PICTURE,
//FILE PROCESS
GET_FILE_LIST = 2001,
DELETE_FILE,
//SETTINGS
SET_VIDEO_RESOLUTION = 3001,
GET_VIDEO_RESOLUTION,
SET_GSENSOR ,
GET_GSENSOR ,
SET_PARKING ,
GET_PARKING,
SET_AUTO_RECORD,
GET_AUTO_RECORD,
SET_SOUNDINDICATOR,
GET_SOUNDINDICATOR,//3010
SET_LOOPING,
GET_LOOPING,
SET_LANGUAGE,
GET_LANGUAGE,
SET_WIFI,
GET_WIFI,
SET_TIME,
GET_SD_INFO,
FORMAT_SD,
FACTORY_RESET,//3020
GET_DEVICE_INFO,
GET_ALL_SETTINGS,
ADJUST,
ADJUST_CONTINUOUS,
//NOTIFY
NOTIFY = 4001
} app_cmd_t; typedef struct app_data{
app_cmd_t type;
int fd;
int id ;
char code[APP_PARA_LEN];
char value[APP_PARA_LEN];
}app_data_t; //return msqid if success
extern int initIpcMsg(key_t msqkey);
//remove a msq
extern int exitIpcMsg(key_t msqkey); //send ipc msg
extern int sendIpcMsg(key_t msqkey, const ipc_msg_t *msg);
//recv ipc msg
extern int recvIpcMsg(key_t msqidkey, ipc_msg_t *msg); #ifdef __cplusplus
} #endif/*end of _cplusplus*/ #endif/*end of H_MSGIPC_H*/

对应的ipcmsg.c如下:

/*ipcmsg.c*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <errno.h>
#include "ipcmsg.h" //return msqid if success
int initIpcMsg(key_t msqkey)
{
int msqid = -1; msqid=msgget(msqkey,IPC_EXCL); /*check msq*/
if(msqid < 0){
msqid = msgget(msqkey,IPC_CREAT|0666);/*create msq*/
if(msqid <0){
perror("failed to create msq");
return -1;
}
}
else
{
printf("msqid %d exist\n", msqid);
return -2;
} return msqid;
} //remove a msqid
int exitIpcMsg(key_t msqkey)
{
int msqid = -1; msqid=msgget(msqkey,IPC_EXCL); /*check msq*/
if(msqid <0){
perror("failed to get msq");
return -1;
} return msgctl(msqid,IPC_RMID,0); //remove msq
} int sendIpcMsg(key_t msgkey, const ipc_msg_t *msg)
{
char str[256];
int ret = 0, msqid =0; if(NULL == msg)
return -1;
msqid=msgget(msgkey,IPC_EXCL); /*检查消息队列是否存在*/
if(msqid < 0){
perror("failed to create msq");
return -2;
} ret= msgsnd(msqid,msg,sizeof(ipc_msg_t ),IPC_NOWAIT);
if ( ret< 0 ) {
perror("msgsnd() write msg failed");
}
return ret;
} /*
return byte of msg if success
else reurn less than 0 */
int recvIpcMsg(key_t msgkey, ipc_msg_t *msg)
{
int msgid = 0,ret = 0;
char str[512]; //first check parameter
if(NULL == msg)
return -1; //second check if the msgqueue exit
msgid = msgget(msgkey,IPC_EXCL );
if(msgid < 0){
//perror("msq not existed!");
return -2;
}
//third get msg
ret= msgrcv(msgid,msg,sizeof(ipc_msg_t),msg->type,0);
if(ret < 0)
perror("get msg failed"); return ret;
}

接下来测试用的demon分为三个文件,一个send用来发送数据 一个recv用来接收数据 还有一个service(用来启动和结束消息队列)

服务启动端service.c

/*service.c*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <errno.h>
#include "ipcmsg.h" #ifdef IPCST
int main()
{
ipc_msg_t msg = {.type = APP_MSG,};
int ipc_msg_type = APP_MSG;
app_data_t adat = {.type = 3021, .fd =12, .id =8};
int msqid = 0; msqid=initIpcMsg(MSGKEY); /*init msq*/
if(msqid < 0){
return -1;
} printf("start ipc key 0x%x msqid %d\n", MSGKEY, msqid); sleep(20);
printf("exit ipc key 0x%x msqid %d\n", MSGKEY, msqid); return exitIpcMsg(MSGKEY); //remove msq }
#endif

service.c

发送端send.c

/*send.c*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <errno.h>
#include "ipcmsg.h"
#include <string.h> #ifdef IPCSND
int main()
{
ipc_msg_t msg = {.type = APP_MSG,};
int ipc_msg_type = APP_MSG;
app_data_t adat = {.type = GET_DEVICE_INFO, .fd =12, .id =8,.code="App ", .value="Test"};
int msqid = 0;
int i = 0; msqid=msgget(MSGKEY,IPC_EXCL); /*check msq*/ while(msqid < 0){
printf("wait msq key 0x%x\n",MSGKEY);
sleep(1);
msqid=msgget(MSGKEY,IPC_EXCL); /*check msq*/
} while(i ++ < 10)
{
adat.id = i;
memcpy(msg.buf,&adat,sizeof(adat));
sendIpcMsg(MSGKEY,&msg);
printf("send %d msg\n", i);
//sleep(1);
}
printf("send exit %d\n", msqid); return 0;
}
#endif

send.c

接收端recv.c

/*receive.c */
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <errno.h>
#include "ipcmsg.h"
#include <string.h> #ifdef IPCRCV
int main()
{
const long type = APP_MSG;
app_data_t data = {};
ipc_msg_t msg = {};
while(1)
{
msg.type = type;
if(recvIpcMsg(MSGKEY, &msg) > 0)
{
memcpy(&data, msg.buf, sizeof(data));
printf("cmd %u fd %d id %d code :%s value: %s\n", data.type, data.fd, data.id, data.code, data.value);
}
else
{
//printf("recv msg failed key 0x%x\n",MSGKEY);
sleep(1);
}
}
return 0;
}
#endif

recv.c

根据说明将接受函数和发送函数改成如下

        ret= msgsnd(msqid,msg,BUF_SIZE,IPC_NOWAIT);
ret= msgrcv(msgid,msg,BUF_SIZE,msg->type,0);

改完之后再次编译执行,mmp依然报告同样的错误,说明问题的正因不是这个,但是这确实是个错误,犯了经验注意,一般这种借口习惯性以为就是漆面的那个msg的总大小。以前也是这样用了没报过错误。。。

又继续检索,在下面这个帖子里发现了一条线索

https://bbs.csdn.net/topics/390809159

其中提到的

应该是这个结构体定义的有问题:DMOMsg
设置成员变量udwMsgID的时候,msgsnd发送的消息,需要的那个mttype是个非法值
struct mymsg {
long int mtype; /* message type */
char mtext[1]; /* message text */
};
可以定义个这样的结构体,第一个mtype不要写成负数
原文中这么说的:The structure member mtype is a non-zero positive type long int that can be used by the receiving process for message selection.
看看这个里面的解释:http://pubs.opengroup.org/onlinepubs/007908799/xsh/msgsnd.html

这里面说mtype不要写成负数,但是根据手册说明应该是非零值而不仅是不能是负数

又去仔细看了一下man手册

原文如下:

The mtype field must have a strictly positive integer value.  This value can be used by the receiving process for message selec‐
tion (see the description of msgrcv() below).

原话说的是mtype必须是一个严格的正整数,也就是意味着0也是一个非法的。

还有另一个地方也有说明 message type, must be > 0

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

再回头去看看我初始化的type是APP_MSG,而APP_MSG就一个枚举类型默认第一个,那不就是0

typedef    enum ipc_msg_type
{
APP_MSG,
INPUT_MSG,
GPS_MSG
}ipc_type;

这个APP_MSG默认就是个0。

于是赶紧改一下初始值

typedef    enum ipc_msg_type
{
APP_MSG=0xF0,
INPUT_MSG,
GPS_MSG
}ipc_type;

再次编译执行,果然OK。

查来查去还是man手册才是葵花宝典。

所以以上总共犯了两个经验错误:

           struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
};
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);

1、size的参数指的是msg中的buf的大小而非msg的大小——虽然目前这个用错了还没出现严重错误,但还是应该严格根据接口说明来使用。

2、mtype必须是大于0的整数,必须是大于0的整数,必须是大于0的整数,重要的事情说三遍。

事实上type必须大于0,文档中说的是为了用于接受进程的选择。

在man 一下msgrecv

   msgrcv()
The msgrcv() system call removes a message from the queue specified by msqid and places it in the buffer pointed to by msgp. The argument msgsz specifies the maximum size in bytes for the member mtext of the structure pointed to by the msgp argument. If the message text has
length greater than msgsz, then the behavior depends on whether MSG_NOERROR is specified in msgflg. If MSG_NOERROR is specified, then the message text
will be truncated (and the truncated part will be lost); if MSG_NOERROR is not specified, then the message isn't removed from the queue and the system
call fails returning -1 with errno set to E2BIG. The argument msgtyp specifies the type of message requested as follows: * If msgtyp is 0, then the first message in the queue is read. * If msgtyp is greater than 0, then the first message in the queue of type msgtyp is read, unless MSG_EXCEPT was specified in msgflg, in which case the
first message in the queue of type not equal to msgtyp will be read. * If msgtyp is less than 0, then the first message in the queue with the lowest type less than or equal to the absolute value of msgtyp will be read.
接收函数
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
有个参数是msqtyp
如果msqtyp=0 读取队列里的第一条消息
如果msqtyp>0 读取队列里面mtype=msqtyp的第一条消息
如果msqtyp<0 读取队列里面mtype最接近于(等于或小于)msqtyp绝对值的那条消息

所以如果在发送的时候type出现了小于0或者等于0的mtype,那么后面读取的时候msqtyp就没法实现选择。

进程间通信消息队列msgsnd执行:Invlid argument——万恶的经验主义的更多相关文章

  1. PHP 进程间通信——消息队列(msg_queue)

    PHP 进程间通信--消息队列 本文不涉及PHP基础库安装.详细安装说明,请参考官网,或期待后续博客分享. 1.消息队列函数准备 <?php//生成一个消息队列的key$msg_key = ft ...

  2. linux进程间通信消息队列:msgsnd: Invalid argument

    今天写了个消息队列的小测试程序结果send端程序总是出现:msgsnd: Invalid argument,搞了半个小时也没搞明白,后来查资料发现我将(st_msg_buf.msg_type = 0; ...

  3. Linux进程间通信—消息队列

    四.消息队列(Message Queue) 消息队列就是消息的一个链表,它允许一个或者多个进程向它写消息,一个或多个进程向它读消息.Linux维护了一个消息队列向量表:msgque,来表示系统中所有的 ...

  4. linux进程间通信-消息队列

    一 消息队列的介绍 消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法. 每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构. 我们可以通过发送消息来避免命名管道的 ...

  5. Linux进程间通信-消息队列(mqueue)

    前面两篇文章分解介绍了匿名管道和命名管道方式的进程间通信,本文将介绍Linux消息队列(posix)的通信机制和特点. 1.消息队列 消息队列的实现分为两种,一种为System V的消息队列,一种是P ...

  6. Linux下进程间通信--消息队列

    消息队列的定义遍地都是,不想移驾,请看下文: 一.定义: 消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法. 每个数据块都被认 为是有一个类型,接收者进程接收的数据块可以有不同的类型值.我 ...

  7. 详解linux进程间通信-消息队列

    前言:前面讨论了信号.管道的进程间通信方式,接下来将讨论消息队列. 一.系统V IPC 三种系统V IPC:消息队列.信号量以及共享内存(共享存储器)之间有很多相似之处. 每个内核中的 I P C结构 ...

  8. IPC进程间通信---消息队列

    消息队列 消息队列:消息队列是一个存放在内核中的消息链表,每个消息队列由消息队列标识符标识.与管道不同的是消息队 列存放在内核中,只有在内核重启(即操作系统重启)或者显式地删除一个消息队列时,该消息队 ...

  9. Linux 进程间通信 消息队列 实现两个进程间通信

    例子: 通过消息队列实现两个进程间通信,一个进程从终端输入数据,通过消息队列发送,另一个进程通过消息队列接收数据 文件1 创建进程1 终端输入通过消息队列发送数据 #include <stdio ...

随机推荐

  1. 【转载】小心 int 乘法溢出!

    C/C++ 语言里, 绝大部分平台上 int 类型是 32 位的, 无论你的操作系统是否是 64 位的. 而一些常用的函数, 如 malloc(), 它接受的参数是 size_t 类型: void * ...

  2. VMware ESXi 7.0 U2 SLIC 2.6 & Unlocker 集成 Intel NUC 网卡、USB 网卡和 NVMe 驱动

    ESXi 7 U2 标准版镜像集成 NUC 网卡.USB 网卡 和 NVMe 驱动. 请访问原文链接:https://sysin.org/blog/vmware-esxi-7-u2-nuc-usb-n ...

  3. 个人作业--体温上报APP

    第一阶段目标: 1.要求增加用户注册功能,用户注册信息包括用户ID(学号).用户名(姓名),手机号码,用户单位(班级),用户班级四项基本信息,用户第一次注册后,用户姓名不用每次输入 . 2.体温上报界 ...

  4. 【多线程】Android多线程学习笔记——线程池

    Java线程池采用了享元设计模式,在系统中维持一定数量的线程,用于处理异步或并发需求,在平时处理异步或并发任务时被广泛使用.这里基于JDK1.8和Android28来整理一些关于线程池的知识点. 一. ...

  5. UI自动化测试:App的Webview页面元素左滑

      一.前言 在做App自动化测试时,我们会遇到如上图所示的列表数据页面左滑删除场景,一般可以通过location.rect方法获取对应列表的元素坐标,然后使用TouchAction或者swipe滑动 ...

  6. 告别Kafka Stream,让轻量级流处理更加简单

    一说到数据孤岛,所有技术人都不陌生.在 IT 发展过程中,企业不可避免地搭建了各种业务系统,这些系统独立运行且所产生的数据彼此独立封闭,使得企业难以实现数据共享和融合,并形成了"数据孤岛&q ...

  7. requests访问页面时set-cookie获取cookie

    import requests headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:57.0) Gecko/ ...

  8. Nresource服务之接口缓存化

    1. 背景 Nresource服务日均4.5亿流量,考虑到未来流量急增场景,我们打算对大流量接口进行缓存化处理:根据服务管理平台数据统计显示getUsableResoureCount接口调用量很大,接 ...

  9. NOI.AC#2007-light【根号分治】

    正题 题目链接:http://noi.ac/problem/2007 题目大意 \(n\)个格子排成一排,每个格子有一个\(0/1\)和一个颜色.开始每个格子都是\(0\),\(q\)次操作取反一个颜 ...

  10. Python3入门系列之-----异常处理

    前言 作为 Python 初学者,在刚学习 Python 编程时,经常会看到一些报错信息,在前面我们没有提及,这章节我们会专门介绍. Python 有两种错误很容易辨认:语法错误和异常. Python ...