2013年6月4日 星期二

Named Pipes的實作

[概述]

簡單來說就是一個windows幫你建好、已經可以用的queue,可以塞資料進去然後依序再把它拿出來,也可以支援雙面塞入和取出(雙插頭?!)。它的好處在於可以同時一直拿資料也可以一直塞資料,所以通常可用在不同Thread做資料傳送使用。

[架構]

主要分為Server端和Client端,下面實作是由Server端從Pipe收資料,Client端則是把資料塞到Pipe裡
我們Server端的步驟是:
1. 創建一個Name pipe
2. 跟Client做connect
3. 開始從Pipe讀資料出來
4. 收完資料以後要記得Disconnect和關Handle

Client端步驟則為:
1. 與伺服器作connect動作
2. 將Server端創好的Name pipe開起來(如開檔案)
3. 寫寫寫,寫東西到Pipe
4. 寫完收工關Handle

[實作]

Server端:

以\.\Pipe\Test當Name為例,m_hPipe是成員變數

步驟1.
m_hPipe = CreateNamedPipe("\\\\.\\Pipe\\Test", PIPE_ACCESS_DUPLEX,
                           PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
                           1, 1000, 1000, 1000, NULL);    // 創建Named Pipe
if (m_hPipe == INVALID_HANDLE_VALUE)
    ::AfxMessageBox(_T("Create Named Pipe fail."));

步驟2.
由於接下來要做的Connect步驟會一直等待Client端的連線,所以從這裡之後必須另外開一個Thread來執行此部分,所以另外創建一個ServerProc
if ( !ConnectNamedPipe(pView->m_hPipe, NULL))             // 等待Client Connect
{
    CloseHandle(pView->m_hPipe);                          // 失敗要關閉Handle
    ::AfxMessageBox(_T("Connect Named Pipe fail."));
    return false;
}

步驟3.
Connect上以後就是開始做讀取的動作了,讀取動作跟讀檔案是完全一樣的,
阿要讀幾次就看個人,看你是要寫迴圈一直讀還是啥都可以,不過要記得跳離開就是了。
這裡範例就只讀一次這樣。

char strBuffer[1024] = {0};
DWORD ReadNum;
if ( !ReadFile(pView->m_hPipe, strBuffer, sizeof(strBuffer), &ReadNum, NULL))
{
    CloseHandle(pView->m_hPipe);                          // 失敗要關閉Handle
    ::AfxMessageBox(_T("Read Pipe fail."));
}

CString CStrTemp;
CStrTemp = strBuffer;
::AfxMessageBox(CStrTemp);

步驟4.
打完收工要記得Disconnect和關閉Handle,不然會挫賽
if (DisconnectNamedPipe(pView->m_hPipe))                  // 終止Server連線
{
    CloseHandle(pView->m_hPipe);                          // 關閉Pipe
    pView->m_hPipe = NULL;
}
else
    ::AfxMessageBox(_T("Disconnect Named Pipe fail"));

return true;

Client端:

Client端的部分可以開個Thread去丟資料,總之不要跟Server是同Thread就是了,這樣才不會Block住。
步驟1.
跟Server connect的方式是使用WaitNamedPipe
注意的是,這個動作要比Server端的ConnectNamedPipe執行才可以,不然會錯亂。

if ( !WaitNamedPipe("\\\\.\\Pipe\\Test", NMPWAIT_WAIT_FOREVER)) // 等待Server連線
{
    ::AfxMessageBox(_T("Wait Pipe Fail."));
    return false;
}

步驟2.
使用CreateFile(開檔案的方式)來創建一個Handle供後來寫入Pipe使用

HANDLE hPipe = CreateFile("\\\\.\\Pipe\\Test", GENERIC_WRITE, 0, NULL,
                           OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hPipe == INVALID_HANDLE_VALUE)
{
    ::AfxMessageBox(_T("Open Pipe Fail."));
    return false;
}

步驟3.
透過剛剛創建的Handle將資料寫入Pipe
寫入的方式也是使用寫檔的WriteFile來實現

CString CStrMessage = _T("Test message.");                // 測試傳送的字串
DWORD WriteNum;
if( !WriteFile(hPipe, CStrMessage , CStrMessage .GetLength(), &WriteNum, NULL))
{
    ::AfxMessageBox(_T("Write Message to Pipe Fail."));
    return false;
}

步驟4.
打完收工記得關Handle

CloseHandle(hPipe);                                       // 關閉handle

就介紹到這裡囉~下回見

2012年5月7日 星期一

使用Notepad++ 跑 Ruby

1. 首先第一步要先安裝Ruby
    至Ruby官網下載最新穩定版並安裝
    windows預設的目錄應該為 C:\Ruby(版本號)\
    ex: 以小弟的版本來說 預設路徑為 C:\Ruby193\

2. 安裝完成後打開cmd(命令提示字元)看看能不能直接下 ruby -v 這個指令,如果不行則必須
    至windows添加環境變量,然後重開機
    環境變量添加方法: 點選我的電腦右鍵選擇內容 > 進階系統設定 > 環境變數 > 系統變數
                                     > 找到變數 Path > 點選後在最後面加上路徑
                                     以小弟來說則填上  ;C:\Ruby193\bin
  加完環境變量重開機後記得在測試看看下 ruby -v 這個指令是否可以work

2012年4月30日 星期一

如何讓VC產生的exe可單獨執行

VC 產生的 exe 無法單獨執行的原因在於編譯時 library 沒有使用靜態編譯的關係,所以在
沒有安裝 VC 開發程式的電腦上會因為找不到 library而發生錯誤,只要我們將編譯改成靜
態編譯後,再將有問題的lib處理好即可。

方法如下:
1. 從工具列選擇Project > Properties

2. 選擇 Configuration Properties > General Use of MFC選項
    改成 Use MFC in a Static Library

3. Configuration Properties > Linker > Input
    先Ingnore Specific Library 打上 uafxcwd.lib libcmtd.lib
    再Additional Dependenies 打上 uafxcwd.lib libcmtd.lib
    (Library可能會隨著Debug不同而改變)