可变长度数据的管道实现方法

本文介绍了如何实现一个可变长度数据的管道通信方式,适用于Windows环境。通过共享内存和事件机制,确保进程间完整消息的传输,避免部分消息读取。当写入速度超过读取速度时,提出了两种处理策略,并强调了读写过程中检查和避免错误结果的重要性。
摘要由CSDN通过智能技术生成

管道是两个进程之间的一种通讯方式。比如甲和乙之间有一个管道存在,则甲可以不断往管道中存入消息,而乙则可以顺序获取到消息,若没有消息时则阻塞。在项目实践中,管道是一种很实用的两个进程之间的通讯方式。

在实践中,可能需要这样一种管道,这个管道传输的是可变长度的消息,传输信息的两个进程甲、乙,传输的实际上是一个完整的消息。这个消息由头部和数据构成,头部描述当前消息的长度、类型以及其它信息,而数据则是不固定长度的。若甲写入一个消息,则乙只能获取到这么一个完整的消息或者消息未来到而阻塞等待,不可能仅仅获取到消息的一部分。


在windows环境下,这个管道可以用共享内存+事件实现。共享内存实现两个进程间消息的传输,事件则用于两个进程的交互。这个共享内存可以设置的比较大,比如128K大小,写方进程写入若干不等长的消息,当到头时再返回到共享内存起始位置重头写入。每次写入必是一个完整的消息,在共享内存里是连续存放的。读方进程则从共享内存起始位置开始读取消息,读入一个头部,再读入所有数据。这样每次获取的都是一个完整的消息。当写方进程写入一个消息时,则触发一次事件,通知读方有消息可用。读方在读取的时候需要查看是否有可用消息,若无则等待写方的事件。

这里有这样一个问题,当写方速度比读方速度快时,则可能会有写方写入的消息覆盖未读取的消息,这里可以有两种方法,写方阻塞,直到有可用内存,或者写入失败返回。

这里需要注意的就是,当写方在管道末端写入消息的时候,可能空间不足,这时候只能回到开始位置。需要注意的是,在写入消息的前方可能有进程在读取消息,这时候必须加以检查,否则会出现错误结果。

对于读取消息的进程而言,在管道末端读取最后一个消息的时候,也必须检查,是否为最后一个消息。若是则等待,否则转到起始位置读取,这时候也需要检查。

代码如下所示。

ct_connection.h

#ifndef CT_CONNECTION_H
#define CT_CONNECTION_H
/**
*说明:
*作者:***
*最近修改时间:2014-12-16
*版本:1.7
*/

#ifdef __cplusplus
extern "C"
{
#endif

	/************************************************************************/

#define CT_VERSION 0x0107

	//通讯关闭
#define CT_CLOSE 9527

	//所有的消息类型, 按大小顺序排列,修改时必须保证顺序
#define CT_MSG_ALL {CT_TYPE_1, CT_TYPE_2,CT_TYPE_3,CT_TYPE_4}
	//信息类型个数,不包括CLOSE
#define CT_TYPE_NUM 4

#define CT_TYPE_1 1
#define CT_TYPE_2 4
#define CT_TYPE_3 7
#define CT_TYPE_4 9

//消息头部
typedef struct st_CtMessage{
	unsigned int  type;    //类型
	void*         buf;     //数据缓冲区
	unsigned long length;  //数据长度
	unsigned long exData1; //附加数据1
	unsigned int  exData2; //附加数据2
}CtMessage;
/************************************************************************/

//某类型的头部说明
#define CT_HEADER(pCtMsg, type) ((type*)(&(pCtMsg)->buf))

/************************************************************************/


/************************************************************************/


//信息接收处理函数
//参数:pCtMsg  接收到的信息
//参数:context  用户传入的参数
//返回:若有对该类型的消息进行处理则返回SUCCESS,否则返回FAIL
typedef int(*doReceiveFunc)(const CtMessage*pCtMsg, void*context);

/***/
//场景设置=>实时的通讯通道
#define C2T "c2t"
//实时=>场景设置的通讯通道
#define T2C "t2c"
/***/

//打开发送通道,参数open是通道名
int OpenCtSend(const char*open);
//打开接收通道,参数receive是接收的通道名
 int OpenCtReceive(const char*receive, doReceiveFunc func, void*context);
//关闭发送通道,会导致接收方停止接收
int CloseCtSend();
//关闭接收通道
int CloseCtReceive();

int SendCtMessage(CtMessage*pCtMsg);

/*方案一,回调式, 设置接收到数据时的回调函数,第二个参数context是该函数调用时传入的第二个参数*/
int SetCtRecvCallBack(doReceiveFunc func, void*context);//设置接收回调


#ifdef __cplusplus
}
#endif

#endif


 ct_connection.c

#include <windows.h>
#include <wchar.h>
#include <stdio.h>
#include <assert.h>
//#include <rtcapi.h>
#include "ct_connection.h"
#include "../commonHeader/util.h"
#include "../commonHeader/charWchar.h"
#include "ct_event_sm.h"

//打印允许
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值