windows10使用VS(VC++)創建c++多進程命名管道通信


代碼可以在 這里 下載
代碼主要涉及到:

  • 管道通信
  • 多線程(含臨界區)
  • 多進程通信
  • 創建的子進程獨立運行

更新日志

04-12-2020
  1. 去除自定義函數返回值,改為int作為函數返回值並增加相應的說明
  2. pipe_create_win函數改名為pepe_create,用法不變
  3. write函數額外增加一個參數,意義:吐出實際發送數據長度,函數的返回值表明當前調用函數狀態:成功or失敗
  4. pipe_helper類的析構函數增加異常處理,避免析構函數出現異常而造成程序異常中斷運行,內存未能釋放的現象。
  5. 匿名管道通信沒有測試;Linux下的管道通信正在路上......

  24-09-2020 
  接收線程,增加創建事件

 1. (18:27 15/9/2020) 增加cmake版本

lib_pipe


1. 關於

lib_pipe是一個用c++編寫的管道通信動態庫,截至目前(15/9/2020),完成了Windows上的收發。創建這個項目的初衷:

  • 現在有一個main程序,需要創建1個或者多個子進程,每個子進程都有自己的活兒要干,且,創建子進程時,還需要讀取每個進程的配置文件
  • main程序需要支持控制子進程的退出
    之前沒有做過這樣的需求,都是多線程玩的嗨。彌補多進程知識....

2. 目錄說明

.
├───Debug		// exe的輸出路徑,目前,exe編譯環境:win10 1909 + VS2015up3
│   ├───1		// 子進程1所需文件
│   ├───2		// 子進程2所需文件
│   └───3		// 子進程3所需文件
├───demo_create // client項目,創建一個子進程的程序
├───lib_pipe	// 管道通信項目,動態庫
└───main		// main項目,負責調用client子進程  

3. 項目說明

  • 3.1 main項目將創建子進程,新創建的子進程獨立運行

  • 3.2 創建的子進程所需文件在Debug目錄下的1、2和3目錄

  • 3.3 main進程將與子進程采用管道通信

  • 3.4 main將發送Q通知子進程結束,子進程收到Q后,釋放自己創建時申請的一些資源,再退出

  • 3.5 lib_pipe, 目前(15/9/2020)僅支持Windows,后期將持續完善,簡單封裝了常用操作,歡迎指正,一起完善

  • 3.6 解決方案是用VS2015 up3創建的,若嘗試用低於這個版本的VS打開項目,請創建一個空的解決方案,再添加項目即可

  • 3.7 代碼中使用 nullptr 關鍵字,請選擇支持對應所需的編譯器

  • 3.8 main項目和 demo_create 都使用lib_pipe, 動態庫名字和目錄,配置到了VS的項目屬性中。因為lib輸出到Debug目錄下,所以將lib目錄配置為:${TargetDir}

4.lib_pipe使用

按照習慣,封裝了以下操作:

  • init-初始化管道信息
  • wrie-向管道寫入數據
  • uninit-釋放初始化申請的資源
  • on_recv_data-接收數據(單獨創建了一個線程接收數據

文件,包括,lib庫文件,dll動態庫,和頭文件,頭文件名: pipe_interface.h

5. 返回值說明

注意: 04-12-2020更新中已經摒棄自定義函數返回值
c++11引入了tuple,但是當初考慮到需要兼容不支持c++11的環境,故換作了std::pair作為函數的返回值,以便能獲取更多有效的信息。
之前以int為函數的返回值,通過定義各種數值對應其結果,比如0-成功,1,字符串為空,2-文件不存在之類的。
lib_pipe使用的返回值聲明如下:
相關說明,請到文件按【pipe_interface.h】查看源碼。

6. 接收

  • 接收需要繼承類【irecv_data】,並實現函數【on_recv_data】
  • 初始化函數 init的第二個參數需要傳遞為繼承【ipipe_interface】類的對象
  • 不需要接收,傳遞NULL即可

7.一個例子(非完整)

lib_pipe的用法可以在項目 main 和 demo_create中找到,包括收發。

  • 初始化
pipe_param_base base_param;
base_param._to_create_pipe = false;
base_param._name = std::string("\\\\.\\pipe\\ReadPipe");
ret_type ret_val = pipe.init(base_param);
if (0 != ret_val.id())
{
	std::cout << "error id = " << ret_val.id() << ", str = " << ret_val.str().c_str() << "\n\n";
}
else
{
	cout << "子進程 " << argv[0] << " 創建管道成功...\n";
}

  • 寫入數據(發送)
const char arr_send[] = "Q";	/// 子進程約定收到 Q 就結束進程
for (int i = 0; i < pipe_count_3; i++)
{
	cout << "\n\n正在發送:";
	ret_type ret_val = pipe_arr[i].write(arr_send, sizeof(arr_send));
	if (0 != ret_val.id())
	      cout << "i = " << i << ", 發送失敗,id = " << ret_val.id() << "\n\n";
	else
	      cout << "i = " << i << ", 發送成功,id = " << ret_val.id() << "\n\n";
}
  • 釋放
pipe.uninit();
  • 接收
    接收需要重寫函數 on_recv_data
void on_recv_data(const char *pdata, const unsigned int len_recv_data)
{
	cout << "\n\n進程: " << str_process_name.c_str() << " 收到數據了: " << len_recv_data << "\n";
	cout << "進程: " << str_process_name.c_str() << "收到的數據是:";
	for (unsigned int i = 0; i < len_recv_data; i++)
	{
		cout << pdata[i];
	}
	// 約定 第一個字符為Q,退出
	if ('Q' == pdata[0])
	{
		EnterCriticalSection(&cs_proc_is_end);
		process_is_end = true;
		LeaveCriticalSection(&cs_proc_is_end);
	}
}

8. License

BSD licenses

9. 運行結果


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM