• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            記錄一些學(xué)習(xí)小事

            Work hard

            統(tǒng)計(jì)

            留言簿

            閱讀排行榜

            評(píng)論排行榜

            進(jìn)程通信——郵槽和命名管道

            今天記錄下自己學(xué)的郵槽和命名管道,學(xué)習(xí)過程中遇到點(diǎn)問題也拿出來分享下。哈  開整
            先說一下大體的概念?yuàn)W。

            郵槽定義

            郵槽(Mailslot)也稱為郵件槽,是Windows 提供的進(jìn)程間通信的手段,

            其提供的是基于不可靠的,郵件槽只支持單向數(shù)據(jù)傳輸,也就是服務(wù)器只能接收數(shù)據(jù),而客戶端只能發(fā)送數(shù)據(jù),

            何為服務(wù)端?創(chuàng)建郵槽的那一端就是服務(wù)端。
            還有需要提及的一點(diǎn)是,客戶端在使用郵槽發(fā)送數(shù)據(jù)的時(shí)候只有當(dāng)數(shù)據(jù)的長度 < 425 字節(jié)時(shí),

            才可以被廣播給多個(gè)服務(wù)器,如果消息的長度 > 425 字節(jié)的話,那么在這種情形下,郵槽是不支持廣播通信的。
            這是我看到的郵槽的簡要說明吧。
            先說下郵槽的使用過程吧。然后再分析函數(shù),在貼代碼。非常簡單哦
            服務(wù)端:                                        客戶端:
            首先創(chuàng)建郵槽CreateMailslot               打開油槽CreateFile
            讀取數(shù)據(jù) ReadFile                           寫入數(shù)據(jù)WriteFile
            完事了,只有這四個(gè)函數(shù)。也很容易理解。 客戶端寫入數(shù)據(jù) 服務(wù)端讀取數(shù)據(jù)。
            CreateMailslot(_T("\\\\.\\mailslot\\chenxiao"),0, MAILSLOT_WAIT_FOREVER,NULL);
            第一個(gè)參數(shù)是個(gè)固定格式\\.\\mailslot\\name   點(diǎn)代表本機(jī)。mailslot是硬編碼 不能變,name可以自己起個(gè)郵槽的名字。‘\’放入字符串中要用轉(zhuǎn)義字符\
            所以就寫成了"\\\\.\\mailslot\\chenxiao"
            第二個(gè)參數(shù)To specify that the message can be of any size, set this value to zero. 設(shè)置成0
            第三個(gè)參數(shù)為了下面的讀取操作應(yīng)該等待的時(shí)間 MAILSLOT_WAIT_FOREVER 傳這個(gè)代表參數(shù)代表永久等待。
            最后一個(gè)參數(shù)安全屬性 嘎嘎 null
            ReadFile(hMailSlot,pData,sizeof(TCHAR)*80,&dByteRead,NULL);
            這幾個(gè)參數(shù)很簡單了。第一個(gè)參數(shù)就是創(chuàng)建郵槽返回來的句柄 第二個(gè)參數(shù)一個(gè)[out]buffer用來接收從郵槽中讀出來的東東。第三個(gè)參數(shù)就是讀取多少個(gè)字節(jié)。
            第四個(gè)參數(shù)基本沒用,是一個(gè)[out]的LPDWord  很蛋疼只能DWORD dByteRead; 然后傳個(gè)他的地址。
            因?yàn)閙sdn上說了If lpOverlapped is NULL, lpNumberOfBytesRead cannot be NULL;
            lpoverlapped就是我們的最后一個(gè)參數(shù),這個(gè)參數(shù)可以設(shè)置同步和異步,如果文件打開模式是FILE_FLAG_OVERLAPPED這個(gè)的話,我們這個(gè)就不可以是NULL
            這個(gè)同步異步問題我在下面的命名管道中在說。這里就先過去。這個(gè)參數(shù)設(shè)成NULL。
            客戶端函數(shù)
            CreateFile(_T("\\\\.\\mailslot\\chenxiao"),GENERIC_WRITE,FILE_SHARE_READ,NULL,CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,NULL);
            這幾個(gè)參數(shù)也很容易理解了。第一個(gè)參數(shù)要和創(chuàng)建郵槽的時(shí)候的參數(shù)一樣。如果要遠(yuǎn)程通信的話可以把‘.’設(shè)置成服務(wù)器 主機(jī)名 或者在一個(gè)區(qū)域內(nèi)廣播‘*’
            但是我用兩個(gè)機(jī)器實(shí)驗(yàn)了,沒有成功,目前我只能用郵槽在本地一個(gè)機(jī)器上通信。。。尷尬。。有知道怎么在兩個(gè)機(jī)器上通信的,要給我留言教教我哦。
            后幾個(gè)參數(shù)根據(jù)參數(shù)名大家就可以猜個(gè)差不多了,我就不說了。吼吼。
            WriteFile(hMailSlot,str,sizeof(TCHAR)*80,&dByteWrite,NULL);這個(gè)函數(shù) 跟 readfile差不多 就是向郵槽中寫入數(shù)據(jù)用的。
            第二個(gè)參數(shù)是要寫入的內(nèi)容,第三個(gè)是大小(以字節(jié)為單位).
            好了這幾個(gè)函數(shù)都說完了。貼上小代碼,就清晰了。

            //服務(wù)器端 我用的c++寫的。
            #include <iostream>
            #include 
            <Windows.h>
            #include 
            <tchar.h>
            using namespace std;


            int main()
            {
                HANDLE hMailSlot
            =CreateMailslot(_T("\\\\.\\mailslot\\chenxiao"),0,
                    MAILSLOT_WAIT_FOREVER,NULL);
                 TCHAR pData[
            80];
                 ZeroMemory(pData,
            sizeof(TCHAR)*80);
                 DWORD dByteRead;
                 
            while(1)
               
            {
                     BOOL b
            =ReadFile(hMailSlot,pData,sizeof(TCHAR)*80,&dByteRead,NULL);
                      wprintf_s(_T(
            "%s\n"),pData);
                 }

                
                system(
            "pause");
                
            return 0;
            }
            //客戶端我在mfc中寫的。
            void CclientDlg::OnBnClickedButtonSend()
            {
                 TCHAR str[
            80];
                ZeroMemory(str,
            sizeof(TCHAR)*80);
                 GetDlgItem(IDC_EDIT_INPUT)
            ->GetWindowText(str,70);
                 DWORD dByteWrite;
                 HANDLE hMailSlot
            =CreateFile(_T("\\\\.\\mailslot\\chenxiao"),GENERIC_WRITE,FILE_SHARE_READ,NULL,CREATE_ALWAYS,
                     FILE_ATTRIBUTE_NORMAL,NULL);
                
            if (hMailSlot==INVALID_HANDLE_VALUE)
                
            {
                    MessageBox(_T(
            "createfile失敗,請(qǐng)打開服務(wù)器"));
                    
            return ;
                }

                 BOOL b
            =WriteFile(hMailSlot,str,sizeof(TCHAR)*80,&dByteWrite,NULL);
                 GetDlgItem(IDC_EDIT_INPUT)
            ->SetWindowText(_T(""));
                 CloseHandle(hMailSlot);
            }


            這就是運(yùn)行結(jié)果啦。這個(gè)東西沒啥大用。就是學(xué)習(xí)一下而已。以后萬一用到也能弄弄。

            下面我說下命名管道。這個(gè)東西坑了我一下午。。。
            郵槽建立的是無連接的通信。。那么命名管道 就是有鏈接的可靠的通信了。他跟郵槽挺相似的。但是比郵槽好很多。
            同上面。我粘一些概念性的東西。

            命名管道是通過網(wǎng)絡(luò)來完成進(jìn)程之間的通信的,命名管道依賴于底層網(wǎng)絡(luò)接口,

            其中包括有 DNS 服務(wù),TCP/IP 協(xié)議等等機(jī)制,但是其屏蔽了底層的網(wǎng)絡(luò)協(xié)議細(xì)節(jié),

            對(duì)于匿名管道而言,其只能實(shí)現(xiàn)在父進(jìn)程和子進(jìn)程之間進(jìn)行通信,而對(duì)于命名管道而言,

            其不僅可以在本地機(jī)器上實(shí)現(xiàn)兩個(gè)進(jìn)程之間的通信,還可以跨越網(wǎng)絡(luò)實(shí)現(xiàn)兩個(gè)進(jìn)程之間的通信。

            命名管道使用了 Windows 安全機(jī)制,因而命名管道的服務(wù)端可以控制哪些客戶有權(quán)與其建立連接,

            而哪些客戶端是不能夠與這個(gè)命名管道建立連接的。

            利用命名管道機(jī)制實(shí)現(xiàn)不同機(jī)器上的進(jìn)程之間相互進(jìn)行通信時(shí),

            可以將命名管道作為一種網(wǎng)絡(luò)編程方案時(shí),也就是看做是 Socket 就可以了,

            它實(shí)際上是建立了一個(gè)客戶機(jī)/服務(wù)器通信體系,并在其中可靠的傳輸數(shù)據(jù)。

            命名管道的通信是以連接的方式來進(jìn)行的,

            服務(wù)器創(chuàng)建一個(gè)命名管道對(duì)象,然后在此對(duì)象上等待連接請(qǐng)求,

            一旦客戶連接過來,則兩者都可以通過命名管道讀或者寫數(shù)據(jù)。          

            命名管道提供了兩種通信模式:字節(jié)模式和消息模式。

            在字節(jié)模式下,數(shù)據(jù)以一個(gè)連續(xù)的字節(jié)流的形式在客戶機(jī)和服務(wù)器之間流動(dòng),

            而在消息模式下,客戶機(jī)和服務(wù)器則通過一系列的不連續(xù)的數(shù)據(jù)單位,進(jìn)行數(shù)據(jù)的收發(fā),

            每次在管道上發(fā)出一個(gè)消息后,它必須作為一個(gè)完整的消息讀入。

            我相信很多人看了幾句就跳到這里來了。。概念性的東西 確實(shí)太不好玩了。我也不愛看。。哈哈
            介紹命名管道需要的函數(shù)。
            服務(wù)器端

            CreateNamedPipe 創(chuàng)建命名管道

             ConnectNamedPip  連接
            ReadFile    讀
            WriteFile  寫

            客戶端

            WaitNamedPipe 查看命名管道
            CreateFile  打開命名管道
            WriteFile ReadFile  寫   讀

            就這些東西,今天由于不仔細(xì)看msdn 寫程序?qū)懨闪恕!!5葧?huì)我在說啊。大家要注意哦。
            CreateNamedPipe(_T("\\\\.\\pipe\\chenxiao"),PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED,PIPE_TYPE_BYTE,1,1024,1024,2000,NULL);
            很多參數(shù)啊!不怕不怕 慢慢來
            第一個(gè)我略過了哦。第二個(gè)大家在msdn上可以看到有
            PIPE_ACCESS_DUPLEX   讀寫雙向
            PIPE_ACCESS_INBOUND   數(shù)據(jù)只能從客戶端到服務(wù)端
            PIPE_ACCESS_OUTBOUND  和上面那個(gè)相反
            這個(gè)參數(shù)我們?cè)O(shè)置成 第一個(gè)。然而通過msdn大家可以看到這個(gè)參數(shù)可以附加 flag  我們就附加FILE_FLAG_OVERLAPPED 這個(gè)了
            MSDN那一大堆英文我也瞅不太明白,大至意思就是這個(gè)呢 用了這個(gè)參數(shù) 程序操作讀,寫,連接等操作,可以立馬返回。比如說讀一個(gè)大文件吧

            你把這個(gè)文件從頭讀到偉 需要很長時(shí)間。這樣的話你的readfile函數(shù)就不會(huì)反回  就會(huì)阻塞在那里一直讀。這樣很不好,所以有了這個(gè)參數(shù)。這個(gè)參數(shù)就是使你的讀 寫 等待函數(shù)立馬返回,這個(gè)就屬于程序的異步,這個(gè)讀函數(shù)和主程序一起執(zhí)行。
            下一個(gè)參數(shù)就是以字節(jié)流還是消息方式發(fā)送文件 讀取文件。我們采用字節(jié)流方式PIPE_TYPE_BYTE。
            下一個(gè)參數(shù)是最多可以創(chuàng)建幾個(gè)命名管道 比如我們?cè)O(shè)置成3,就是可以創(chuàng)建3個(gè)這樣的管道。我們這里設(shè)置成1,我們只用一個(gè)管道做演示就行。然后是分配的輸入 輸出 緩沖區(qū)大小 ,就類似創(chuàng)建線程時(shí)分配棧空間大小一樣。然后是一個(gè)超時(shí)時(shí)間設(shè)置 這個(gè)設(shè)置成0就可以。最后一個(gè)NULL安全屬性

            ConnectNamedPipe服務(wù)端的連接管道函數(shù)這個(gè)函數(shù)兩個(gè)參數(shù)第一個(gè)參數(shù)句柄,第二個(gè)參數(shù)一個(gè)結(jié)構(gòu)體對(duì)象
            這個(gè)結(jié)構(gòu)體呢 里面有一個(gè)事件句柄。剛才上邊由于設(shè)置了異步,所以你要有一個(gè)標(biāo)志著讀結(jié)束的標(biāo)志,這個(gè)標(biāo)志就用的這個(gè)事件。創(chuàng)建這個(gè)事件要設(shè)置成手動(dòng)的,初始為無信號(hào)。

            這樣服務(wù)端的就寫完了。
            然后再說一下客戶端的函數(shù)
            WaitNamedPipe(_T("\\\\.\\pipe\\chenxiao"),0);
            這個(gè)函數(shù)呢就屬于一個(gè)查看函數(shù),看看有沒有叫chenxiao的命名管道
            大家不要認(rèn)為這個(gè)函數(shù)可以打開命名管道 或者連接管道
            大家從msdn上可以看到這句話If the function succeeds,the process should use the CreateFile function to open a handle to the named pipe
            今天我由于沒看到這句話苦苦弄了一個(gè)下午也沒連上管道5555555555
            在客戶端可以用waitnamedpipe檢查下有沒有這個(gè)管道 然后再createfile打開它。
            哦了 搞定了。搞上我的代碼瞅瞅效果。

             

            //服務(wù)器端的代碼  MFC寫的

            void CPipeServerDlg::OnBnClickedButtonCreate()
            {
                m_hNP
            =CreateNamedPipe(_T("\\\\.\\pipe\\chenxiao"),
                    PIPE_ACCESS_DUPLEX
            |FILE_FLAG_OVERLAPPED,
                    PIPE_TYPE_BYTE,
            1,1024,1024,0,NULL);
                
            if (m_hNP==INVALID_HANDLE_VALUE)
                
            {
                    MessageBox(_T(
            "創(chuàng)建管道失敗"));
                }

                
            else
                
            {
                    MessageBox(_T(
            "創(chuàng)建管道成功"));
                }

                
            //連接-----------------------------
                
                OVERLAPPED op;
                ZeroMemory(
            &op,sizeof(OVERLAPPED));
                op.hEvent
            =CreateEvent(NULL,TRUE,FALSE,NULL);
                BOOL b
            =ConnectNamedPipe(m_hNP,&op);
                
            if (WaitForSingleObject(op.hEvent,INFINITE)==0)
                
            {
                    MessageBox(_T(
            "connect成功 haha"));
                }

                
            else
                
            {
                    MessageBox(_T(
            "create fail"));
                }

            }


            void CPipeServerDlg::OnBnClickedButtonWrite()
            {

                TCHAR buff[
            100]=_T("來自服務(wù)器的信息");
                DWORD d;
                WriteFile(m_hNP,buff,
            200,&d,NULL);
            }


            void CPipeServerDlg::OnBnClickedButtonRead()
            {
                TCHAR buff[
            100];
                ZeroMemory(buff,
            200);
                DWORD d;
                ReadFile(m_hNP,buff,
            200,&d,NULL);
                MessageBox(buff);
            }

             

            //客戶端的代碼 MFC寫的


            void CPipeClientDlg::OnBnClickedButtonOpenpipe()
            {
                BOOL b
            =WaitNamedPipe(_T("\\\\.\\pipe\\chenxiao"),0);
                
            //BOOL b=1;
                m_hFile = CreateFile(_T("\\\\.\\pipe\\chenxiao"), 
                    GENERIC_READ 
            | GENERIC_WRITE,
                    
            0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
                
            if (!b||m_hFile==INVALID_HANDLE_VALUE)
                
            {
                    MessageBox(_T(
            "連接失敗"));
                }

                
            else
                
            {
                    MessageBox(_T(
            "連接成功"));
                }

            }


            void CPipeClientDlg::OnBnClickedButtonRecieve()
            {
                TCHAR buff[
            100];
                ZeroMemory(buff,
            200);
                DWORD d;
                ReadFile(m_hFile,buff,
            200,&d,NULL);
                MessageBox(buff);
            }


            void CPipeClientDlg::OnBnClickedButtonSend()
            {
                TCHAR buff[
            100]=_T("client's message");
                DWORD d;
                WriteFile(m_hFile,buff,
            200,&d,NULL);
            }

            下圖程序運(yùn)行效果圖

            哇卡卡阿卡














             

            posted on 2011-08-01 22:14 陳曉 閱讀(5354) 評(píng)論(6)  編輯 收藏 引用

            評(píng)論

            # re: 進(jìn)程通信——郵槽和命名管道 2011-08-02 12:18 yotta123

            沒事還是不要用油槽!  回復(fù)  更多評(píng)論   

            # re: 進(jìn)程通信——郵槽和命名管道 2011-08-02 12:35 陳曉

            恩,我上邊也說了,沒什么大用,就是供學(xué)習(xí)用用。書上都說什么可以廣播什么的方便,但是我用這玩意兩臺(tái)機(jī)器通信都沒搞上。。@yotta123
              回復(fù)  更多評(píng)論   

            # re: 進(jìn)程通信——郵槽和命名管道 2013-12-31 21:33 MeiJi

            樓主好,剛才試了一下在管道的實(shí)例中,其他正常,但是服務(wù)器的讀或者client的接受函數(shù)會(huì)出錯(cuò),然后調(diào)試的時(shí)候發(fā)現(xiàn)readfile()第一個(gè)參數(shù)句柄無效(調(diào)試直接彈出中斷或繼續(xù)對(duì)話框),不曉得為什么。write();的句柄是有效地。忘答復(fù),謝謝  回復(fù)  更多評(píng)論   

            # re: 進(jìn)程通信——郵槽和命名管道 2014-10-11 16:56 Mr zhang

            最好還是封裝一下。  回復(fù)  更多評(píng)論   

            # re: 進(jìn)程通信——郵槽和命名管道 2015-07-22 14:50 sad

            MeiJi用戶,我覺得是不是你的事件對(duì)象搞錯(cuò)了,這里是自動(dòng)復(fù)位,初始為無信號(hào),等待連接再激活這個(gè)信號(hào),如果開始為有信號(hào)經(jīng)過重疊對(duì)象可能會(huì)出錯(cuò)  回復(fù)  更多評(píng)論   

            # re: 進(jìn)程通信——郵槽和命名管道 2015-07-22 14:54 sad

            樓主!你的命名通道試過兩臺(tái)電腦通訊過嗎?成功沒?我都沒試過,全在自己電腦上調(diào)試的‘  回復(fù)  更多評(píng)論   


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            欧美久久久久久精选9999| 一本久久a久久精品综合香蕉| AV狠狠色丁香婷婷综合久久 | 一本色道久久综合| 无码伊人66久久大杳蕉网站谷歌| 亚洲综合婷婷久久| 久久www免费人成看片| 久久99精品国产一区二区三区| 人妻丰满?V无码久久不卡| 看久久久久久a级毛片| 久久五月精品中文字幕| 一本色道久久综合亚洲精品| 狠狠久久综合| .精品久久久麻豆国产精品| 亚洲伊人久久综合中文成人网 | 亚洲国产精品无码久久青草 | 久久婷婷色香五月综合激情 | 国产精品青草久久久久福利99 | 伊人久久大香线蕉亚洲五月天| 久久精品免费一区二区三区| 亚洲欧美日韩中文久久| 色天使久久综合网天天| 国产高潮国产高潮久久久91 | 久久香蕉综合色一综合色88| 亚洲中文字幕久久精品无码喷水| 午夜福利91久久福利| 办公室久久精品| 青草影院天堂男人久久| 国产99久久精品一区二区| 久久久久99精品成人片直播| 久久综合亚洲鲁鲁五月天| 欧美激情精品久久久久久| 久久久精品视频免费观看 | 亚洲国产欧美国产综合久久| 伊人久久大香线蕉无码麻豆| 久久久久99精品成人片三人毛片| 93精91精品国产综合久久香蕉| 久久久久久a亚洲欧洲aⅴ| 久久这里只有精品首页| 国产成人无码精品久久久免费| 久久综合九色综合久99|