C++:進程間通訊(部分轉載,個人整理)

/**
 * 主題:多線程和多進程技術
 *
 */
Q1: C++進程間通訊的方式
    管道(命名管道,匿名管道),socket,事件event,共享內存,消息隊列

實例:命名管道實例

/**
 * 方案如下所示
 * 管道服務端:CreateNamedPipe(創建管道HANDLE hPipe) -> ConnectNamedPipe(連接客戶端)-> (WriteFile)往管道寫數據/(readFile)往管道讀數據
 * 管道客戶端: WaitNamedPipe(等待命名管道實例有效,設置超時時間) -> CreateFile(打開管道,返回命名管道句柄) -> (WriteFile)往管道寫數據/(readFile)往管道讀數據
 * 小結:api函數:CreateNamePipe,ConnectNamedPipe,WaitNamedPipe.CreateFile,WriteFile,ReadFile
 */


#include "stdafx.h"  
#include <stdio.h>  
#include <windows.h>  
#include <ctime> 

int main(int argc,_TCHAR *argv[])
{
    srand(time(NULL));

    char buf[256] = "";
    DWORD rlen = 0;

    HANDLE hPipe = CreateNamedPipe(
            TEXT("\\\\.\\Pipe\\mypipe"),                        //管道名       
            PIPE_ACCESS_DUPLEX,                                 //管道類型   
            PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE|PIPE_WAIT,  //管道參數  
            PIPE_UNLIMITED_INSTANCES,                           //管道能創建的最大實例數量  
            0,                                                  //輸出緩衝區長度 0表示默認  
            0,                                                  //輸入緩衝區長度 0表示默認  
            NMPWAIT_WAIT_FOREVER,                               //超時時間  
            NULL);

    if(INVALID_HANDLE_VALUE == hPipe)
    {
        printf("Create Pipe Error(%d)\n",GetLastError()); 
    }
    // 創建命名管道成功
    else
    {
        //阻塞等待客戶端連接
        printf("Waiting For Client Connection...\n");  

        if(ConnectNamedPipe(hPipe,NULL) == null)
        {
            printf("Connection failed!\n");   
        }
        else
        {
            printf("Connection Success!\n");  
        }

        // 進程間數據通訊
        while(true)
        {
            // 接收客戶端發送過來的內容
            if(ReadFile(hPipe,buf,256,&rlen,NULL) == FALSE)
            {
                printf("Read Data From Pipe Failed!\n");  
                break;  
            }
            // 向客戶端發送內容
            else
            {
                printf("From Client: data = %s, size = %d\n", buf, rlen);  
                char wbuf[256] = "";  
                sprintf(wbuf, "%s%d", wbuf, rand()%1000);  
                DWORD wlen = 0; 

                WriteFile(hPipe,wbuf,sizeof(buf),&wlen,0);  
                printf("To Client: data = %s, size = %d\n", wbuf, wlen);  
                Sleep(1000);  
            }
        }
        CloseHandle(hPipe);  // 關閉管道
    }

    system("PAUSE");
}

// 命名管道客戶端
#include "stdafx.h"  
02.#include <stdio.h>  
03.#include <windows.h>  
04.#include <ctime>  
05.  
06.int main(int argc, _TCHAR* argv[])  
07.{  
08.    srand(time(NULL));  
09.  
10.    DWORD wlen = 0;  
11.    Sleep(1000);//等待pipe的創建成功!  
12.  
13.    BOOL bRet = WaitNamedPipe(TEXT("\\\\.\\Pipe\\mypipe"), NMPWAIT_WAIT_FOREVER);  
14.  
15.    if (!bRet)  
16.    {  
17.        printf("connect the namedPipe failed!\n");  
18.        return 0;  
19.    }  
20.  
21.    HANDLE hPipe=CreateFile(            //管道屬於一種特殊的文件  
22.        TEXT("\\\\.\\Pipe\\mypipe"),    //創建的文件名  
23.        GENERIC_READ | GENERIC_WRITE,   //文件模式  
24.        0,                              //是否共享  
25.        NULL,                           //指向一個SECURITY_ATTRIBUTES結構的指針  
26.        OPEN_EXISTING,                  //創建參數  
27.        FILE_ATTRIBUTE_NORMAL,          //文件屬性(隱藏,只讀)NORMAL爲默認屬性  
28.        NULL);                          //模板創建文件的句柄  
29.  
30.    if (INVALID_HANDLE_VALUE == hPipe)  
31.    {  
32.        printf("open the exit pipe failed!\n");  
33.    }  
34.    else  
35.    {  
36.        while(true)  
37.        {  
38.            char buf[256] = "";  
39.            sprintf(buf,"%s%d",buf,rand()%1000);  
40.            if(WriteFile(hPipe,buf,sizeof(buf),&wlen,0)==FALSE) //向服務器發送內容  
41.            {  
42.                printf("write to pipe failed!\n");  
43.                break;  
44.            }  
45.            else  
46.            {  
47.                printf("To Server: data = %s, size = %d\n", buf, wlen);  
48.                char rbuf[256] = "";  
49.                DWORD rlen = 0;  
50.                ReadFile(hPipe, rbuf, sizeof(rbuf), &rlen, 0);  //接受服務發送過來的內容  
51.                printf("From Server: data = %s, size = %d\n", rbuf, rlen);  
52.            }  
53.            Sleep(1000);  
54.        }  
55.        CloseHandle(hPipe);//關閉管道  
56.    }  
57.  
58.    system("PAUSE");  
59.    return 0;  
60.}  

實例:socket(此處代碼重點在互斥體,實現對共享資源的訪問保護)

ex:socket的客戶端,多線程實例,訪問共享資源

#include <iostream>
#include <Winsock2.h>
#include <list>
#include <string>
#include <cstdio>

#paramea comment(lib,"Ws2_32.lib")

using namespace std;

/**
 * @:全局變量,供多個子線程訪問
 */
list<string> str_a;
list<string> str_b;
list<string> str_c;

/**
 * @:加鎖訪問共享資源(互斥鎖)
 */
HANDLE Lock(LPCWSTR name)
{
    HANDLE mutex;

    // 首先訪問互斥鎖,獲取互斥體對象句柄(openmutex)。若失敗則創建互斥對象,否則等待獲取此互斥對象的控制權(WaitForSingleObject)
    mutext = openmutex(MUTEXT_ALL_ACCESS,FALSE,name);
    if(NULL == mutext)
    {
        mutex = CreateMutex(NULL,TURE,name);
    }
    else
    {
        /**
         * WaitForSingleObject函數用來檢測hHandle事件的信號狀態,在某一線程中調用該函數時,線程暫時掛起,如果在掛起的dwMilliseconds毫秒內,線程所等待的對象變爲有信號狀態,則該函數立即返回;
         */
        WaitForSingleObject(hMutex,INFINITE);
    }
    return mutex;
}

/**
 * @:釋放互斥鎖,供其他線程可訪問共享資源
 */
 bool Unlock(HANDLE mutex)
 {
     // 釋放互斥體對象的控制權
     if(0 == ReleaseMutex(mutex)) 
     {
         return false;
     }
     else
     {
         CLoseHandle(mutex);
         mutex = NULL;
         return true;
     }
}

// socket client thread
DWORD WINAPI ClientThread(LPVOID lpParameter)
{
    SOCKET ClientSocket = (SOCKET)lpParameter;
    char recvBuf[1000];

    while(true)
    {
        memset(recvBuf,0x00,sizeof(recvBuf));
        recv(ClientSocket,recvBuf,sizeof(recvBuf),0);

        HANDL mutex_a,mute_b,mutex_c;
        mutex_a = Lock( L"mutex");
        str_a.push_back(string(recvBuf));
        UnLock(mutex_a);

        mutex_b= Lock(L"mutex");
        str_b.push_back(streing(recvBuf));
        Unlock(mutex_b);

        mutex_c = Lock(L"mutex");
        str_c.push_back(string(recvBuf));
        Unlock(mutex_c);
    }

    return 0;
}

DWORD WINAPI AProcess(LPVOID lpParametr)
{
   while(true)
   {
       HANDLE mutex = Lock(L"mutex");
       if(!str_a.empty())
       {
            string str = str_a.front();
            str_a.pop_front();
            printf("A: %s\n", str.c_str());
       }
       Unlock(mutex);
   }
}

DWORD WINAPI BProccess(LPVOID lpParameter)
{
    while(true)
    {
        HANDLE mutex = Lock(L"mutex");
        if (!str_b.empty())
        {
            string str = str_b.front();
            str_b.pop_front();
            printf("B: %s\n", str.c_str());
        }
        Unlock(mutex);
    }
}

DWORD WINAPI CProccess(LPVOID lpParameter)
{
    while(true)
    {
        HANDLE mutex = Lock(L"mutex");
        if (!str_c.empty())
        {
            string str = str_c.front();
            str_c.pop_front();
            printf("C: %s\n", str.c_str());
        }
        Unlock(mutex);
    }
}

int main()
{
// 加載socket動態鏈接庫(dll)
    WORD wVersionRequested;
    WSADATA wsaData;    // 這結構是用於接收Wjndows Socket的結構信息的
    int err;

    wVersionRequested = MAKEWORD( 1, 1 );   // 請求1.1版本的WinSock庫

    err = WSAStartup( wVersionRequested, &wsaData );
    if ( err != 0 ) {
        return -1;          // 返回值爲零的時候是表示成功申請WSAStartup
    }

    if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) {
        // 檢查這個低字節是不是1,高字節是不是1以確定是否我們所請求的1.1版本
        // 否則的話,調用WSACleanup()清除信息,結束函數
        WSACleanup( );
        return -1;
    }

// 創建socket操作,建立流式套接字,返回套接字號sockClient
    // SOCKET socket(int af, int type, int protocol);
    // 第一個參數,指定地址簇(TCP/IP只能是AF_INET,也可寫成PF_INET)
    // 第二個,選擇套接字的類型(流式套接字),第三個,特定地址家族相關協議(0爲自動)
    SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);

// 將套接字sockClient與遠程主機相連
    // int connect( SOCKET s,  const struct sockaddr* name,  int namelen);
    // 第一個參數:需要進行連接操作的套接字
    // 第二個參數:設定所需要連接的地址信息
    // 第三個參數:地址的長度
    SOCKADDR_IN addrSrv;
    addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");      // 本地迴路地址是127.0.0.1;
    addrSrv.sin_family = AF_INET;
    addrSrv.sin_port = htons(8000);
    connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));

    HANDLE hThread = CreateThread(NULL, 0, ClientThread, (LPVOID)sockClient, 0, NULL);

    HANDLE hThread_a = CreateThread(NULL, 0, AProccess, (LPVOID)NULL, 0, NULL);

    HANDLE hThread_b = CreateThread(NULL, 0, BProccess, (LPVOID)NULL, 0, NULL);

    HANDLE hThread_c = CreateThread(NULL, 0, CProccess, (LPVOID)NULL, 0, NULL);

    while(true);

    printf("End linking...\n");
    closesocket(sockClient);
    WSACleanup();   // 終止對套接字庫的使用

    printf("\n");
    system("pause");
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章