BufferedIpc

这是我以前写的一个做IPC的类。因为是C++的,所以仅做参考了。

对外有三个函数:

 bool init(const string& name, int size, DWORD initTimeout)
 int send(LPVOID Buffer, int size)
 int receive(LPBYTE& Buffer)

任何一方调init时就建立file mapping了。init中的size只是缓冲区大小,这个大小发送方和接收方必须一致;实际发送接收时,如果超出缓冲区大小时会自动分多次发送;发送完一段之后接收方会收到一个event可以开始读入。然后发送方用send, 接收方receive就可以了。receive会在读完所有数据之后返回创建的buffer。

初始化时可以指定等待event的timeout时间。初始化之后无论谁发送接收都是可以的。

///////////////////////////////////////////////////////////////////////////////
class BufferedIpc
{
public:
 BufferedIpc()
 {
  id = 0;
  hCanWriteEvent[0] = hCanWriteEvent[1] = NULL;
  hCanReadEvent[0] = hCanReadEvent[1] = NULL;
  hFileMap = NULL;
  mapView = NULL;
 }
 ~BufferedIpc()
 {
  for(int i = 0; i < 2; i++)
  {
   if (hCanWriteEvent[i]) CloseHandle(hCanWriteEvent[i]);
   if (hCanReadEvent[i]) CloseHandle(hCanReadEvent[i]);
  }
  if (mapView)
   UnmapViewOfFile(mapView);
  if (hFileMap)
   CloseHandle(hFileMap);
 }
 //Init with a shared name (must be unique), and the maximum size that can send at once.
 bool init(const string& name, int size, DWORD initTimeout)
 { 
  char buf[MAX_PATH];
  shareName = name;
  bufferSize = size + sizeof(BufferHead);
  timeout = initTimeout;
  // First try to open mapped file
  hFileMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, shareName.c_str());
  
  id = (hFileMap == NULL) ? 0 : 1;
  
  if (hFileMap == NULL)
  {
   // allocate a mapped file area for internal data storage
   // and for IPC buffer exchange
   hFileMap = CreateFileMapping((HANDLE)-1, NULL,  PAGE_READWRITE,  NULL,
    bufferSize,
    shareName.c_str());
   if (hFileMap == NULL)
   {
    return false;
   }
  }
  
  mapView = MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, bufferSize);
  for(int i = 0; i < 2; i++)
  {
   sprintf(buf, "%s_CANWRITE_%d", shareName.c_str(), i);
   hCanWriteEvent[i] = fetchEvent(buf, TRUE);
   
   sprintf(buf, "%s_CANREAD_%d", shareName.c_str(), i);
   hCanReadEvent[i] = fetchEvent(buf, FALSE);
  }
  return true;
 }
 
 //No limit on the send and receive size. Return sent size.
 int send(LPVOID Buffer, int size)
 {
  BufferHead bh;
  bh.totalSize = size;
  bh.thisPackSize = 0;
  bh.remainSize = size;
  while(bh.remainSize > 0)
  {
   if (WaitForSingleObject(hCanWriteEvent[id], timeout) != WAIT_OBJECT_0) break;
   
   bh.thisPackSize = min(bufferSize - (int)sizeof(BufferHead), bh.remainSize);
   bh.remainSize -= bh.thisPackSize;
   
   //Write head.
   memcpy(mapView, &bh, sizeof(BufferHead));
   // Then some memory.
   memcpy((LPBYTE)mapView + sizeof(BufferHead), (LPBYTE)Buffer + bh.totalSize - bh.remainSize - bh.thisPackSize, bh.thisPackSize);
   
   // Signal that there is something to read
   SetEvent(hCanReadEvent[1 - id]);
  }
  return bh.totalSize - bh.remainSize;
 }
 //Returns: bytes received, and buffer will be automatically allocated if received at least 1 byte.
 int receive(LPBYTE& Buffer)
 {
  BufferHead bh;
  bool first = true;
  Buffer = NULL;
  memset(&bh, 0, sizeof(bh));
  // Anything there to read?
  while(true)
  {
   if (WaitForSingleObject(hCanReadEvent[id], timeout) != WAIT_OBJECT_0) break;
   
   // Read from mapped memory
   memcpy(&bh, mapView, sizeof(BufferHead));
   if (first && bh.totalSize)
   {
    Buffer = new BYTE[bh.totalSize];
    first = false;
   }
   if (bh.thisPackSize)
    memcpy((LPBYTE)Buffer + bh.totalSize - bh.remainSize - bh.thisPackSize, 
     (LPBYTE)mapView + sizeof(BufferHead), bh.thisPackSize);
   
   SetEvent(hCanWriteEvent[1 - id]);
   if (bh.remainSize == 0) break;
  }
  
  return bh.totalSize; 
 }
protected:
 //The common shared name. used to create file, event.
 string  shareName;
 //Id can only 0 or 1. If it created file, then 0. otherwise 1.
 int  id;
 // Size of the mapping file.
 int  bufferSize;
 //timeout while waiting for events. can be INFINITE.
 DWORD timeout;
 //Handle of the file map file.
 HANDLE hFileMap;
 LPVOID mapView;
 HANDLE hCanWriteEvent[2];
 HANDLE  hCanReadEvent[2];
 //For large data pack, we need to separate the packages. Thus use this one.
 struct BufferHead
 {
  //Total data size.
  int totalSize;
  //This packet size.
  int thisPackSize;
  //Total size still remains. If it equals 0, then we are done.
  int remainSize;
 };
 HANDLE fetchEvent(const string& name, BOOL signaled)
 {
  HANDLE h;
  
  // Try to open mutex
  h = OpenEvent(EVENT_ALL_ACCESS,  FALSE, name.c_str());
  
  // event not found ? create it
  if (h == NULL)
   h = CreateEvent(NULL, FALSE, signaled, name.c_str());
  return h;
 }
}; //BufferedIpc

posted on 2004-07-10 22:53  阿呆  阅读(433)  评论(0编辑  收藏  举报

导航