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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

进程间通信 - 邮槽实现

發布時間:2024/4/11 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 进程间通信 - 邮槽实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

引子

前面的一篇博文介紹了進程之間通信的一種最為簡單的方式,

也就是在本地進程之間通過剪貼板來實現進程間通信,而剪貼板自有其缺陷,

很顯然的是,剪貼板只能在本地機器上實現,

無法實現本地進程與遠程服務器上的進程之間的通信,

那么有沒有辦法實現本地進程和遠程進程的通信呢?

辦法自然是有的,要是實在搞不出,

我拿?Socket?來實現本地進程和遠程進程的通信來實現也是可以的,

但是你想啊,要用?Socket?來實現本地進程和遠程進程之間的通信,

那不僅我要在本地進程中加一堆的?Socket?代碼,

并且服務器上的進程中也是需要加一堆的?Socket?代碼的,

那不搞死人去,也太麻煩了吧,所以不行不行,得換一種方案。

下面就來介紹一種超級無敵簡單的方案,其可以用來實現本地進程與遠程進程之間的通信,

那就是通過郵槽來實現。

???????????

????????????

郵槽定義

郵槽(Mailslot)也稱為郵件槽,其是 Windows 提供的一種用來實現進程間通信的手段,

其提供的是基于不可靠的,并且是單向數據傳輸的服務。

郵件槽只支持單向數據傳輸,也就是服務器只能接收數據,而客戶端只能發送數據,

何為服務端?何為客戶端?

服務端就是創建郵槽的那一端,而客戶端就是已存在的郵件槽的那一端。

還有需要提及的一點是,客戶端在使用郵槽發送數據的時候只有當數據的長度 < 425 字節時,

才可以被廣播給多個服務器,如果消息的長度 > 425 字節的話,那么在這種情形下,

郵槽是不支持廣播通信的。

??????????????

??????????

郵槽的實現

首先是服務端調用?CreateMailslot?函數,這個函數會將創建郵件槽的請求傳遞給內核的系統服務,

也就是?NtCreateMailslot?函數,而?NtCreateMailslotFile?這個函數會到達底層的郵槽驅動程序,

也就是?msfs.sys?,然后一些創建郵槽的工作就交給郵槽驅動程序來完成了,對于底層驅動,這里不作介紹,

而在高層,我們也就只需要調用?CreateMailslot?函數就可以實現創建郵槽了。

????????????

?????????????

郵槽的創建

下面我們就來看看這個?CreateMailslot?函數了:

該函數利用指定的名稱來創建一個郵槽,然后返回所創建的郵槽的句柄。

HANDLE??? WINAPI?? CreateMailslot( ??????? __in????????? LPCTSTR lpName, ??????? __in????????? DWORD nMaxMessageSize, ??????? __in????????? DWORD lReadTimeout, ??????? __in_opt????? LPSECURITY_ATTRIBUTES lpSecurityAttributes );

參數?lpName?指定了將要創建的郵槽的名稱,該名稱的格式必須為?\\.\mailslot\MailslotName

在這里需要注意的是兩個斜杠后的那個?“.”,在這里使用圓點代表的是本地機器,

參數?nMaxMessageSize?用來指定可以被寫入到郵槽的單一消息的最大尺寸,

為了可以發送任意大小的消息,需要將該參數設置為?0?。

參數?lReadTimeOut?指定讀取操作的超時時間間隔,以毫秒作為單位。

讀取操作在超時之前可以等待一個消息被寫入到郵槽中,如果將這個值設置為?0?,那么若沒有消息可用的話,該函數將立即返回。

如果將該值設置為?MAILSLOT_WAIT_FOREVER,則該函數會一直等待,直到有消息可用。

參數?lpSecurityAttributes?一般設置為?NULL?即可,即采用?Windows?默認的針對于郵槽的安全性。

???????????????????????

??????????????

示例:郵槽實現進程間通信

服務端實現:(簡單 MFC 程序)

項目結構:

消息以及成員函數和成員變量的聲明:

// 實現 protected: HICON m_hIcon; ? // 生成的消息映射函數 virtual BOOL OnInitDialog(); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() public: afx_msg void OnBnClickedBtnExit(); afx_msg void OnBnClickedBtnRecv(); afx_msg void OnBnClickedBtnCreate(); ? //定義一個用來創建線程的成員函數 HANDLE CreateRecvThread(LPVOID lpParameter, DWORD threadFlag, LPDWORD lpThreadID); ? //控件變量:用來接收用戶輸入的數據 CEdit m_RecvEdit; ? //成員變量:用來保存創建的郵件槽句柄 HANDLE m_hMailslot;

消息映射表定義:

//用來定義郵槽發送和接收的最大數據字節數 const int maxDataLen = 424; ? //用來接收由客戶端發送過來的數據 char * pStrRecvData; ? CMailSlotServerDlg::CMailSlotServerDlg(CWnd* pParent /*=NULL*/) : CDialogEx(CMailSlotServerDlg::IDD, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); ? m_hMailslot = NULL; ? //給用來接收數據的指針變量分配內存并清為 0 pStrRecvData = new char[maxDataLen]; memset(pStrRecvData, 0, maxDataLen); } ? void CMailSlotServerDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); DDX_Control(pDX, IDC_EDIT_MAILSLOT, m_RecvEdit); } ? BEGIN_MESSAGE_MAP(CMailSlotServerDlg, CDialogEx) ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(ID_BTN_EXIT, &CMailSlotServerDlg::OnBnClickedBtnExit) ON_BN_CLICKED(ID_BTN_RECV, &CMailSlotServerDlg::OnBnClickedBtnRecv) ON_BN_CLICKED(ID_BTN_CREATE, &CMailSlotServerDlg::OnBnClickedBtnCreate) END_MESSAGE_MAP()

消息處理函數:

//退出按鈕的消息處理例程 void CMailSlotServerDlg::OnBnClickedBtnExit() { CDialogEx::OnOK(); } ? //創建按鈕的消息處理 void CMailSlotServerDlg::OnBnClickedBtnCreate() { //創建名為 ZacharyMailSlot 的郵槽 this->m_hMailslot = CreateMailslot(TEXT("\\\\.\\mailslot\\ZacharyMailSlot"), 0, MAILSLOT_WAIT_FOREVER, NULL); ? if(INVALID_HANDLE_VALUE == this->m_hMailslot) { MessageBox(TEXT("創建郵槽失敗 ..."), TEXT("提示"), MB_ICONERROR); return; } } ? //接收按鈕的消息處理 void CMailSlotServerDlg::OnBnClickedBtnRecv() { CString cStrRecvData; DWORD dwRead; ? //創建接收數據的線程,將郵槽句柄傳遞給線程 CreateRecvThread((LPVOID)this->m_hMailslot, 0, NULL); ? cStrRecvData = pStrRecvData; ? this->m_RecvEdit.SetWindowText(cStrRecvData); ? UpdateData(FALSE); } ? //線程處理函數 DWORD WINAPI RecvThreadProc(LPVOID lpPrameter) { HANDLE hRecvMailSlot; DWORD dwRead; ? hRecvMailSlot = (HANDLE)lpPrameter; ? //利用傳進來的郵槽句柄接收收據,并將數據存放到 pStrRecvData 中 if(!ReadFile(hRecvMailSlot, pStrRecvData, maxDataLen, &dwRead, NULL)) { return NULL; } ? //關閉郵槽 CloseHandle(hRecvMailSlot); ? return NULL; } ? HANDLE CMailSlotServerDlg::CreateRecvThread(LPVOID lpParameter, DWORD threadFlag, LPDWORD lpThreadID) { //創建一個線程 return CreateThread(NULL, 0, RecvThreadProc, lpParameter, threadFlag, lpThreadID); }

客戶端實現:(簡單 MFC 程序)

項目結構:

消息以及成員函數和成員變量的聲明:

// 實現 protected: HICON m_hIcon; ? // 生成的消息映射函數 virtual BOOL OnInitDialog(); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() public: afx_msg void OnBnClickedBtnExit(); afx_msg void OnBnClickedBtnSend(); CEdit m_SendEdit;

消息映射表定義:

const int maxDataLen = 424;CMailSlotClientDlg::CMailSlotClientDlg(CWnd* pParent /*=NULL*/): CDialogEx(CMailSlotClientDlg::IDD, pParent) {m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); }void CMailSlotClientDlg::DoDataExchange(CDataExchange* pDX) {CDialogEx::DoDataExchange(pDX);DDX_Control(pDX, IDC_EDIT_SEND, m_SendEdit); }BEGIN_MESSAGE_MAP(CMailSlotClientDlg, CDialogEx)ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(ID_BTN_EXIT, &CMailSlotClientDlg::OnBnClickedBtnExit)ON_BN_CLICKED(ID_BTN_SEND, &CMailSlotClientDlg::OnBnClickedBtnSend) END_MESSAGE_MAP()

消息處理函數:

//退出按鈕的消息處理例程 void CMailSlotClientDlg::OnBnClickedBtnExit() { CDialogEx::OnOK(); } ? ? //發送數據的消息處理例程 void CMailSlotClientDlg::OnBnClickedBtnSend() { UpdateData(); ? if(this->m_SendEdit.GetWindowTextLength() > 0 && this->m_SendEdit.GetWindowTextLength() < maxDataLen) { HANDLE hSendMailSlot; CString cStrSendData; DWORD dwWrite; char * pSendBuf; ? //打開由服務端創建的郵件槽 hSendMailSlot = CreateFile(TEXT("\\\\.\\mailslot\\ZacharyMailSlot"), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); ? if(INVALID_HANDLE_VALUE == hSendMailSlot) { MessageBox(TEXT("打開郵槽失敗 ..."), TEXT("提示"), MB_ICONERROR); return; } ? this->m_SendEdit.GetWindowText(cStrSendData); ? //需要將 Unicode 字符轉換為 ASCII 字符發送 pSendBuf = new char[cStrSendData.GetLength() + 1]; memset(pSendBuf, 0, sizeof(cStrSendData.GetLength() + 1)); for(int i=0;i<cStrSendData.GetLength();i++) { pSendBuf[i] = cStrSendData.GetAt(i); } ? //通過郵件槽向服務端發送數據 if(!WriteFile(hSendMailSlot, pSendBuf, cStrSendData.GetLength(), &dwWrite, NULL)) { MessageBox(TEXT("寫入數據失敗 ..."), TEXT("提示"), MB_ICONERROR); ? CloseHandle(hSendMailSlot); return; } MessageBox(TEXT("寫入數據成功 ..."), TEXT("提示"), MB_ICONINFORMATION); } }

效果展示:

首先啟動服務端進程并單擊創建按鈕:

然后啟動客戶端進程,并在客戶端程序文本框中輸入數據,然后單擊發送按鈕:

然后回到服務端程序中,并且單擊接收按鈕:

從上面的截圖中可以看出,通過郵槽確實實現了從客戶端進程向服務端進程發送數據。

當然上面的?Demo?中的服務端和客戶端都是在本地機器上實現的,

如果想要實現本地進程和遠程進程通信的話,

只需在客戶端調用?CreateFile?打開郵槽時,將下面截圖中標記的圓點置換為遠程服務器的名稱即可以實現了。

???????????

??????????

結束語

對于郵槽呢,其實還是蠻簡單的,

在服務端的話,也就只需要在服務端調用?CreateMailslot?創建一個郵槽,

然后再在服務端調用?ReadFile?來等待讀取數據即可以了,

而在客戶端的話,也就只需要調用?CreateFile?來打開一個已經在服務端創建好的郵槽,

然后再調用?WriteFile?往這個郵槽中寫入數據就可以了。

也就是說,對于郵槽的話,也就那么點東西需要介紹,

但是通過前面的介紹我們也很容易知道,對于通過利用郵槽來實現本地進程和遠程進程的通信還是有缺陷的,

缺陷就是對于郵槽來說,服務端只能接收來自客戶端的數據,而不能給客戶端發送數據,

而客戶端的話,則只能給服務端發送數據,而不能接收服務端發送過來的數據(事實上,服務端也發送不了)。

如果要實現客戶端可以發送數據給服務端,同時也能接收來自服務端的數據,

而服務端也可以發送數據給客戶端,并且服務端也可以接收到來自客戶端的數據的話,

那需要利用另外的進程間通信的手段了,對于這點,留到下一篇博文介紹。

最后的話,那就是今天是 2010? 年的最后一天了,在這里祝諸位節日快樂,2011 會更好 !!!

總結

以上是生活随笔為你收集整理的进程间通信 - 邮槽实现的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。