日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

IPC之命名管道

發(fā)布時間:2023/12/10 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 IPC之命名管道 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1.管道是通過IO接口存取得字節(jié)流, windows中利用得是ReadFile()和WriteFile(),windows利用單一句柄支持雙向IO,命名管道也稱做FIFO(first in first out)
命名管道得機制:一個進程把數(shù)據(jù)放到管道里,另一個知道管道名字得進程把數(shù)據(jù)把取走,實際是用于進程間通信得一段共享內(nèi)存,創(chuàng)建管道得進程稱為管道服務(wù)器,鏈接到一個管道得進程為管道客戶機,用以下函數(shù)?

?

?管道實際是用于進程間通信的一段共享內(nèi)存,創(chuàng)建管道的進程稱為管道服務(wù)器,連
接到-?一個管道的進程為管道客戶機。可以用以下函數(shù)創(chuàng)建管道,即
HANDLB?CreateNamedPipel
LPCTSTR?IpName,
DWORD?dwopenMode,
DWORD?dwPipeMode,
DWORD?nMaxInstances,
DWORD?nOutBufferSi?ze,
DWORD?nInBufferSize,
DWORD?nDefaultrimeOut,
LPSECURITY,ATTRIBUTES?1pSecurityAttributes
);
其中參數(shù)的含義如F:
IpName:?管道名稱。用下面的方法命名;
每一一個命名管道都有一一個唯一的名字以區(qū)分存在于系統(tǒng)的命名對象列表中的其他命
名管道。管道服務(wù)器在調(diào)用CreateNamedPipe()創(chuàng)建命名管道的一一個或多個實例時為其指
定了名稱。對于管道客戶機,則是在調(diào)用CreateFile()或CallINamedPipe()函數(shù)以連接一
個命名管道實例時對管道名進行指定。命名管道的命名規(guī)范與以后介紹的郵槽有些類似,
對其標識也是采用的UNC?格式:
\\[轉(zhuǎn)存失敗重新上傳取消host.name?

]\Pipe\[Path]Name
其中,第-?一部分“\[host_name]”指定了服務(wù)器的名字,命名管道服務(wù)即在此服務(wù)
器創(chuàng)建,其字符串部分可表示為一一個小數(shù)點(表示本機)、星號(當前網(wǎng)絡(luò)字段)、域名
或是一一個真?正的服務(wù);?第二部分“Pipe”與郵槽的“Mailslot”
樣是一一個不可變化的
硬編碼字符串,以表示該文件是從屬于NPFS;?第三部分“[Path]Name"?則使應(yīng)用程序
可以唯一-定義及標識-?一個命名管道的名字,而且可以設(shè)置多級目錄。
dwOpenMode:?管道建方式。可以是下面值的組合:
>?PIPE?ACCESS?INBOUND:?管道只能用作接收數(shù)據(jù)。
4
PIPE?ACCESS?_OUTBOUND:?管道只能用作發(fā)送數(shù)據(jù)。
PIPE.ACCESS_?DUPLEX:?管道既可以發(fā)送也可以接收數(shù)據(jù)。
上面這三三個值只能夠取其中-?一個,同時也可包括以下的-?一個或兩個標識:
管道用于同步發(fā)送和接收數(shù)據(jù),在系統(tǒng)內(nèi)部
FILE?FLAG?WRITE?THROUGH:
對于命名管道的處理上不經(jīng)緩沖區(qū)并能直接發(fā)送,并且只有在數(shù)據(jù)被發(fā)送到目
標地址時發(fā)送函數(shù)才會返回。如果不設(shè)置這個參數(shù),那么需要在數(shù)據(jù)積累到一
定量時才發(fā)送,并且對于發(fā)送函數(shù)的調(diào)用會馬上返回。

?>?FILE?FLAG?OVERLAPPED:?管道可以用于異步輸入和輸出,異步讀寫的有關(guān)
方法和文件異步讀寫是相同的。
dwPipeMode:?命名管道模式。可以是下面值的組合:
>?PIPE_TYPE_BYTE:?數(shù)據(jù)在通過管道發(fā)送時作為字節(jié)流發(fā)送,不能與
PIPE?READMODE?MESSAGE?共用。
PIPE.TYPE.MESSAGE:?數(shù)據(jù)在通過管道發(fā)送時作為消息發(fā)送,不能與
PIPE?READMODE?BYTE?共用。
IPE_READMODE_BYTE:?在接收數(shù)據(jù)時接收字節(jié)流。

PIPE_READMODE_MESSAGE:?在接收數(shù)據(jù)日接收消息。
IPE?_WAIT:?使用等待模式,在讀、寫和建立連接時都需要管道的另-?-方完成相

應(yīng)動作后才會返回。
IPE?NOWAIT:?使用#I?等待模式,在讀、寫和建立連接時不需要管道的另-?一方
完成相應(yīng)動作后就會立即返回。
該管道最大的實例數(shù)量。在第-?一次建立服務(wù)器方管道時這個參數(shù)表
nMaxInstances:
明該管道可以同時存在的數(shù)量。PIPE?UNLIMITED?INSTANCES?表明不對數(shù)量進行
限制。
nOutBufferSize?和nnBufferSize:?輸出和輸入緩沖區(qū)大小。
nDefaultTimeOut:?指定默認的超時時間(以亳秒為單位),如果在創(chuàng)建時設(shè)置為
NMPWAIT.USE?DEFAULT.WAIT?表明無限制的等待,而以后服務(wù)器方的其他管道實例
也需要設(shè)置相同的值。
lpSecurtytltrbutes:?描述安全信息的一一個結(jié)構(gòu),一般設(shè)置為NULL。如果創(chuàng)建或打
開失敗則返回INVALID?HANDLE?VALUE。可以通過GetLastErrort0得到錯誤信息。
其他管道函數(shù)簡介如下所述。
CallNamedPipeO:?連接到一個命名管道,讀取或?qū)懭霐?shù)據(jù)之后關(guān)閉它。
ConnectNamedPipeQ:?服務(wù)進程準備好一個連接到客戶進程的管道,并等待一
個客戶進程連接上為止。
DiscocctNamedPipc:?服務(wù)端用來斷開與客戶端的連接。
GetNamedPipeHandleta?獲取一個命名管道的狀態(tài)信息。
獲取一個命名管道的信息。
GetNamedPipeInfoO
PeekNamedPipeO:?從一個匿名或命名管道中復(fù)制數(shù)據(jù)到一個緩沖區(qū)。
SetNamedPipeHandleStat?設(shè)置管道的類型及其他狀態(tài)信息,比如說是比特
流還是消息流管道。
TransactNamedPipeO:?從一?個消息管道讀?息或向其?寫入肖息。
WaitNamedPipeO:使服務(wù)器進程等待來自客戶的實例連接。
?

?

2.命名管道服務(wù)端與客戶端之間通信的實現(xiàn)流程:

?--?-4.2.2
命名管道服務(wù)端與客戶端之間通信的實現(xiàn)流程一
(1)?連接建立
使用消息管道、郵槽和套接字通信
服務(wù)端通過函數(shù)CreateNamedPipe()創(chuàng)建-?一個命名管道的實例并返回用于今后操作
的句柄,或為已存在的管道創(chuàng)建新的實例。如果在已定義超時值變?yōu)??以前,有一一個實
例管道可以使用,則創(chuàng)建成功并返回管道句柄,并用以偵聽來自客戶端的連接請求,該
功能通過ConneclNamedPipe(實現(xiàn)。
另-?一方面,客戶端通過函數(shù)WaitINamedPipe()使服務(wù)進程等待來自客戶的實例連接。
如果在超時值變?yōu)?以前,有一一個管道可以為連接使用,則WaitNamedPipe()返回TRUE,
并通過調(diào)用CreateFile()或CallINamedPipe()來呼叫對服務(wù)端的連接。此時服務(wù)端將接受客
戶端的連接請求,成功建立連接,服務(wù)端ConnectNamedPipe(返回TRUE,客戶端
CreatcFile()返回-?一個指向管道文件的句柄。
從時序上講,首先是客戶端通過WaitNamedPipe()使服務(wù)端的CreateFile()在限定時間
內(nèi)創(chuàng)建實例成功,然后雙方通過ConnectNamedPipe()和CreateFile()成功連接,并返回用
于通信的文件句柄,此時雙方即可進行通信。
(2)?通信實現(xiàn)
建立連接之后,客戶和服務(wù)端可以通過得到的管道文件句柄利用ReadFile()和
WriteFile()進行彼此間的信息交換。
(3)?連接終止
當客戶端與服務(wù)端的通信結(jié)束,或由于某種原因一一方需要斷開時,客戶端應(yīng)調(diào)用
CloseFile(),而服務(wù)端應(yīng)接著調(diào)用DisconnectNamedPipe。當然服務(wù)端亦可通過單方面
調(diào)用DisconnectNamedPipe()終止連接。最后應(yīng)調(diào)用CloseHandle()來關(guān)閉該管道。
?

?

?

Server端 (1.啟動服務(wù) 創(chuàng)建管道和事件2.創(chuàng)建線程負責(zé)與客戶端通信(利用IO重疊與創(chuàng)建的事件聯(lián)系)。3.接收客戶端數(shù)據(jù)做出計算再反饋到客戶端)
一 啟動服務(wù)StartServer
1.創(chuàng)建管道的名字 CString PipeFullPathData = L"\\\\.\\Pipe\\NamedPipePipe";
2.創(chuàng)建管道 分配事件(因為是NamePipe),通過線程來通信
3.代碼
void CServerDlg::OnBnClickedButtonStartServer()
{
UpdateData(TRUE);
CString PipeFullPathData = L"\\\\.\\Pipe\\NamedPipePipe";


if (m_CEdit_Max_Connect_Count > 0 && m_CEdit_Max_Connect_Count < 100)
{
for (UINT i = 0; i < m_CEdit_Max_Connect_Count; i++)
{
// 創(chuàng)建管道實例
m_UserData[i].PipeHandle = CreateNamedPipe(PipeFullPathData, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, \
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, m_CEdit_Max_Connect_Count, 0, 0, 1000, NULL);
if (m_UserData[i].PipeHandle == INVALID_HANDLE_VALUE)
{
DWORD ErrorCode = GetLastError();
this->MessageBox(L"創(chuàng)建管道錯誤!");
return;
}
// 為每個管道實例創(chuàng)建一個事件對象,用于實現(xiàn)重疊IO
m_UserData[i].EventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
// 為每個管道實例分配一個線程,用于響應(yīng)客戶端的請求
m_UserData[i].ThreadHandle = AfxBeginThread(ThreadProcedure, &m_UserData[i], THREAD_PRIORITY_NORMAL);
}

{
this->SetWindowText(L"命名管道—服務(wù)器(運行)");
this->MessageBox(L"服務(wù)啟動成功");
}
}
}
事件線程函數(shù)(利用的是IO重疊)注意的是BufferData的傳入 兩個或多個數(shù)據(jù)的傳入這樣做

UINT ThreadProcedure(LPVOID ParameterData)
{
DWORD ReturnLength = 0;
char BufferData[0x400] = { 0 };

USER_DATA UserData = *(USER_DATA*)ParameterData;
OVERLAPPED Overlapped = { 0, 0, 0, 0, UserData.EventHandle};

while (1)
{
memset(BufferData, 0, sizeof(BufferData));
// 命名管道的連接函數(shù),等待客戶端的連接(只針對NT)
ConnectNamedPipe(UserData.PipeHandle, &Overlapped);

// 實現(xiàn)重疊I/0,等待OVERLAPPED結(jié)構(gòu)的事件對象
WaitForSingleObject(UserData.EventHandle, INFINITE);

// 檢測I/0是否已經(jīng)完成,如果未完成,意味著該事件對象是人工設(shè)置,即服務(wù)需要停止
if (!GetOverlappedResult(UserData.PipeHandle, &Overlapped, &ReturnLength, true))
break;
// 從管道中讀取客戶端的請求信息
if (!ReadFile(UserData.PipeHandle, BufferData, 0x400, &ReturnLength, NULL))
{
MessageBox(0, L"讀取管道錯誤!", 0, 0);
break;
}
int v1, v2;
sscanf(BufferData, "%d %d", &v1, &v2); //字符串轉(zhuǎn)換為%d
__ServerDlg->m_v1 = v1;
__ServerDlg->m_v2 = v2;
__ServerDlg->m_v3 = v1 + v2;
memset(BufferData, 0, sizeof(BufferData));
sprintf(BufferData, "%d", __ServerDlg->m_v3);//從客戶端到主控端出現(xiàn)
// 把反饋信息寫入管道
WriteFile(UserData.PipeHandle, BufferData, strlen(BufferData), &ReturnLength, NULL);
__ServerDlg->SetDlgItemInt(IDC_EDIT_V1, v1, true);
__ServerDlg->SetDlgItemInt(IDC_EDIT_V2, v2, true);
__ServerDlg->SetDlgItemInt(IDC_EDIT_V3, __ServerDlg->m_v3, true);
// 斷開客戶端的連接,以便等待下一客戶的到來
DisconnectNamedPipe(UserData.PipeHandle);
}

return 0;
}

關(guān)閉服務(wù)
void CServerDlg::OnBnClickedButtonStopServer()
{

DWORD dwNewMode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT;
for (UINT i = 0; i < m_CEdit_Max_Connect_Count; i++)
{
// 設(shè)置重疊I/O的事件,使得工作線程安全結(jié)束
SetEvent(m_UserData[i].EventHandle);
Sleep(1);
CloseHandle(m_UserData[i].ThreadHandle);
CloseHandle(m_UserData[i].PipeHandle);
}

this->SetWindowText(L"命名管道—服務(wù)器(停止)");
this->MessageBox(L"停止啟動成功");
}

Client端(提交數(shù)據(jù)到主控端,主控端反饋最終結(jié)果到客戶端)
void CClientDlg::OnBnClickedButtonSubmitClient()
{
// TODO: 在此添加控件通知處理程序代碼

HANDLE NamedPipeHandle = CreateFile(L"\\\\.\\Pipe\\NamedPipePipe", GENERIC_READ | GENERIC_WRITE, \
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (NamedPipeHandle == INVALID_HANDLE_VALUE)
{
this->MessageBox(L"打開管道失敗,服務(wù)器尚未啟動,或者客戶端數(shù)量過多");
return;
}

DWORD ReturnLength = 0;
char BufferData[0x400] = { 0 };
// 把兩個整數(shù)(a,b)格式化為字符串

m_v1 = GetDlgItemInt(IDC_EDIT_V1);
m_v2 = GetDlgItemInt(IDC_EDIT_V2);
sprintf(BufferData, "%d %d", this->m_v1, this->m_v2);//v1,v2寫入數(shù)組
// 把數(shù)據(jù)寫入管道
WriteFile(NamedPipeHandle, BufferData, strlen(BufferData), &ReturnLength/*寫入地*/, NULL);

memset(BufferData, 0,0x400);//清空
// 服務(wù)器反饋后,讀取服務(wù)器的反饋信息
ReadFile(NamedPipeHandle, BufferData, 0x400, &ReturnLength, NULL);
sscanf(BufferData, "%d", &(this->m_v3));//Client寫入 Server輸出
/*因為是客戶端做運算,然后主控端響應(yīng)再反饋*/
SetDlgItemInt(IDC_EDIT_V3, m_v3, true);

CloseHandle(NamedPipeHandle);

總結(jié)

以上是生活随笔為你收集整理的IPC之命名管道的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。