顯示具有 MFC 標籤的文章。 顯示所有文章
顯示具有 MFC 標籤的文章。 顯示所有文章

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年4月27日 星期五

CString 轉 Char * 轉 string 的方法

在網路上找了很多方法,但始終很難用...
終於讓我找到一個很比較好用的方法來使用~~~
方法如下:

CString 轉 Char*
#define MAX_BUFFER_SIZE 1024

CString CString_Buffer;
char Char_Buffer[MAX_BUFFER_SIZE];
memset(Char_Buffer, 0, MAX_BUFFER_SIZE);   //清空Char_Buffer
int length;
length = CString_Buffer.GetLength(); 

WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK|WC_DEFAULTCHAR, CString_Buffer.GetBuffer(length), 
                    length+1, Char_Buffer, MAX_BUFFER_SIZE, 0, 0);

Char * 轉 CString
CString CString_Buffer;
char test_char[]="test_char";
//使用CString的foemat即可
CString_Buffer.format(_T("%s"), test_char);

Char* 轉 string
string result_string;
char test_char[]="test_char";
//利用assign把*char轉成string
result_string.assign(test_char);

string 轉 Char*
string test_string="test_string";;
char result_char[20];
//透過c_str()轉成str*格式後在複製過去
strcpy(result_char, test_string.c_str());

2012年4月26日 星期四

Critical Section 之用法

Critical Section 之用法

在撰寫多thread 之程式時,有時會碰到不同thread 同時存取一個元件的狀況
而造成這個元件存順序上的錯誤,我們可以透過Critical Section 來解決。

CString

CString::Compare

int Compare( LPCTSTR lpsz ) const;
返回值 字串一樣 返回0
    小於lpsz  返回-1
    大於lpsz  返回1
    區分大小字元
CString s1( "abc" );
CString s2( "abd" );
ASSERT( s1.Compare( s2 ) == -1 );
ASSERT( s1.Compare( "abe" ) == -1 );

CString::CompareNoCase

int CompareNoCase( LPCTSTR lpsz ) const;
返回值 字串一樣 返回0
    
小於lpsz  返回-1
    
大於lpsz  返回1
    
不區分大小字元