欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
Windows系統編程之進(jìn)程間通信_mypage
Windows系統編程之進(jìn)程間通信
2006-08-13 23:08
Windows系統編程之進(jìn)程間通信
作者:北極星2003
來(lái)源:看雪論壇(www.pediy.com)
Windows 的IPC(進(jìn)程間通信)機制主要是異步管道和命名管道。(至于其他的IPC方式,例如內存映射、郵槽等這里就不介紹了)
管道(pipe)是用于進(jìn)程間通信的共享內存區域。創(chuàng )建管道的進(jìn)程稱(chēng)為管道服務(wù)器,而連接到這個(gè)管道的進(jìn)程稱(chēng)為管道客戶(hù)端。一個(gè)進(jìn)程向管道寫(xiě)入信息,而另外一個(gè)進(jìn)程從管道讀取信息。
異步管道是基于字符和半雙工的(即單向),一般用于程序輸入輸出的重定向;命名管道則強大地多,它們是面向消息和全雙工的,同時(shí)還允許網(wǎng)絡(luò )通信,用于創(chuàng )建客戶(hù)端/服務(wù)器系統。
一、異步管道(實(shí)現比較簡(jiǎn)單,直接通過(guò)實(shí)例來(lái)講解)
實(shí)驗目標:當前有sample.cpp, sample.exe, sample.in這三個(gè)文件,sample.exe為sample.cpp的執行程序,sample.cpp只是一個(gè)簡(jiǎn)單的程序示例(簡(jiǎn)單求和),如下:
代碼:
#include  int main() {   int a, b ;   while ( cin >> a >> b && ( a || b ) )     cout << a + b << endl ;   return 0; }

Sample.in文件是輸入文件,內容:
32 433
542 657
0 0
要求根據sample.exe和它的輸入數據,把輸出數據重定向到sample.out
流程分析:實(shí)際這個(gè)實(shí)驗中包含兩個(gè)部分,把輸入數據重定向到sample.exe 和把輸出數據重定向到sample.out。在命令行下可以很簡(jiǎn)單的實(shí)現這個(gè)功能“sample <sample.in >sample.out”,這個(gè)命令也是利用管道特性實(shí)現的,現在我們就根據異步管道的實(shí)現原理自己來(lái)實(shí)現這個(gè)功能。
管道是基于半雙工(單向)的,這里有兩個(gè)重定向的過(guò)程,顯然需要創(chuàng )建兩個(gè)管道,下面給出流程圖:
 
異步管道實(shí)現的流程圖說(shuō)明:
1)。父進(jìn)程是我們需要實(shí)現的,其中需要創(chuàng )建管道A,管道B,和子進(jìn)程,整個(gè)實(shí)現流程分為4個(gè)操作。
2)。管道A:輸入管道
3)。管道B:輸出管道
4)。操作A:把輸入文件sample.in的數據寫(xiě)入輸入管道(管道A)
5)。操作B:子進(jìn)程從輸入管道中讀取數據,作為該進(jìn)程的加工原料。通常,程序的輸入數據由標準的輸入設備輸入,這里實(shí)現輸入重定向,即把輸入管道作為輸入設備。
6)。操作C:子進(jìn)程把加工后的成品(輸出數據)輸出到輸出管道。通常,程序的輸出數據會(huì )輸出到標準的輸出設備,一般為屏幕,這里實(shí)現輸出重定向,即把輸出管道作為輸出設備。
7)。操作D:把輸出管道的數據寫(xiě)入輸出文件
需要注意的是,管道的本質(zhì)只是一個(gè)共享的內存區域。這個(gè)實(shí)驗中,管道區域處于父進(jìn)程的地址空間中,父進(jìn)程的作用是提供環(huán)境和資源,并協(xié)調子進(jìn)程進(jìn)行加工。
程序源碼:
代碼:
#include   #include  const int BUFSIZE = 4096 ;  HANDLE  hChildStdinRd, hChildStdinWr, hChildStdinWrDup,         hChildStdoutRd,hChildStdoutWr,hChildStdoutRdDup,      hSaveStdin,    hSaveStdout;  BOOL CreateChildProcess(LPTSTR);  VOID WriteToPipe(LPTSTR);  VOID ReadFromPipe(LPTSTR);  VOID ErrorExit(LPTSTR);  VOID ErrMsg(LPTSTR, BOOL);  void main( int argc, char *argv[] )  {     // 處理輸入參數   if ( argc != 4 )     return ;   // 分別用來(lái)保存命令行,輸入文件名(CPP/C),輸出文件名(保存編譯信息)   LPTSTR lpProgram = new char[ sizeof(argv[1]) ] ;   strcpy ( lpProgram, argv[1] ) ;   LPTSTR lpInputFile = new char[ sizeof(argv[2]) ];   strcpy ( lpInputFile, argv[2] ) ;   LPTSTR lpOutputFile = new char[ sizeof(argv[3]) ] ;   strcpy ( lpOutputFile, argv[3] ) ;          SECURITY_ATTRIBUTES saAttr;    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);    saAttr.bInheritHandle = TRUE;    saAttr.lpSecurityDescriptor = NULL;        /************************************************    *    redirecting child process‘s STDOUT  *    ************************************************/   hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);       if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0))      ErrorExit("Stdout pipe creation failed\n");         if (! SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr))      ErrorExit("Redirecting STDOUT failed");       BOOL fSuccess = DuplicateHandle(     GetCurrentProcess(),      hChildStdoutRd,         GetCurrentProcess(),      &hChildStdoutRdDup ,     0,         FALSE,         DUPLICATE_SAME_ACCESS);     if( !fSuccess )         ErrorExit("DuplicateHandle failed");     CloseHandle(hChildStdoutRd);      /************************************************    *    redirecting child process‘s STDIN    *    ************************************************/   hSaveStdin = GetStdHandle(STD_INPUT_HANDLE);    if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0))      ErrorExit("Stdin pipe creation failed\n");       if (! SetStdHandle(STD_INPUT_HANDLE, hChildStdinRd))      ErrorExit("Redirecting Stdin failed");       fSuccess = DuplicateHandle(     GetCurrentProcess(),      hChildStdinWr,      GetCurrentProcess(),     &hChildStdinWrDup,      0,      FALSE,                      DUPLICATE_SAME_ACCESS);    if (! fSuccess)      ErrorExit("DuplicateHandle failed");    CloseHandle(hChildStdinWr);      /************************************************    *      創(chuàng )建子進(jìn)程(即啟動(dòng)SAMPLE.EXE)    *    ************************************************/   fSuccess = CreateChildProcess( lpProgram );   if ( !fSuccess )      ErrorExit("Create process failed");       // 父進(jìn)程輸入輸出流的還原設置   if (! SetStdHandle(STD_INPUT_HANDLE, hSaveStdin))      ErrorExit("Re-redirecting Stdin failed\n");    if (! SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout))      ErrorExit("Re-redirecting Stdout failed\n");    WriteToPipe( lpInputFile ) ;   ReadFromPipe( lpOutputFile );            delete lpProgram ;           delete lpInputFile ;           delete lpOutputFile ; }  BOOL CreateChildProcess( LPTSTR lpProgram )  {    PROCESS_INFORMATION piProcInfo;    STARTUPINFO siStartInfo;   BOOL bFuncRetn = FALSE;       ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );   ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );   siStartInfo.cb = sizeof(STARTUPINFO);       bFuncRetn = CreateProcess ( NULL, lpProgram, NULL, NULL, TRUE,                  0, NULL, NULL, &siStartInfo, &piProcInfo);   if (bFuncRetn == 0)    {     ErrorExit("CreateProcess failed\n");     return 0;   }    else    {     CloseHandle(piProcInfo.hProcess);     CloseHandle(piProcInfo.hThread);     return bFuncRetn;   } } VOID WriteToPipe( LPTSTR lpInputFile )  {    HANDLE hInputFile = CreateFile(lpInputFile, GENERIC_READ, 0, NULL,      OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);    if (hInputFile == INVALID_HANDLE_VALUE)      return ;   BOOL fSuccess ;   DWORD dwRead, dwWritten;    CHAR chBuf[BUFSIZE] = {0} ;       for (;;)    {      fSuccess = ReadFile( hInputFile, chBuf, BUFSIZE, &dwRead, NULL) ;     if ( !fSuccess || dwRead == 0)       break;      fSuccess = WriteFile( hChildStdinWrDup, chBuf, dwRead, &dwWritten, NULL) ;     if ( !fSuccess )        break;    }         if (! CloseHandle(hChildStdinWrDup))      ErrorExit("Close pipe failed\n");    CloseHandle ( hInputFile ) ; }  VOID ReadFromPipe( LPTSTR lpOutputFile )  {    HANDLE hOutputFile = CreateFile( lpOutputFile, GENERIC_READ|GENERIC_WRITE,      FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);    if (hOutputFile == INVALID_HANDLE_VALUE)      return ;   BOOL fSuccess ;   DWORD dwRead, dwWritten;    CHAR chBuf[BUFSIZE] = { 0 };       if (!CloseHandle(hChildStdoutWr))      ErrorExit("Closing handle failed");       for (;;)    {      fSuccess = ReadFile( hChildStdoutRdDup, chBuf, BUFSIZE, &dwRead, NULL) ;     if( !fSuccess || dwRead == 0)      {       break;      }     fSuccess = WriteFile( hOutputFile, chBuf, dwRead, &dwWritten, NULL) ;     if ( !fSuccess )        break;    }    CloseHandle ( hOutputFile ) ; }  VOID ErrorExit (LPTSTR lpszMessage)  {    MessageBox( 0, lpszMessage, 0, 0 );  }

二、命名管道
命名管道具有以下幾個(gè)特征:
(1)命名管道是雙向的,所以?xún)蓚€(gè)進(jìn)程可以通過(guò)同一管道進(jìn)行交互。
(2)命名管道不但可以面向字節流,還可以面向消息,所以讀取進(jìn)程可以讀取寫(xiě)進(jìn)程發(fā)送的不同長(cháng)度的消息。
(3)多個(gè)獨立的管道實(shí)例可以用一個(gè)名稱(chēng)來(lái)命名。例如幾個(gè)客戶(hù)端可以使用名稱(chēng)相同的管道與同一個(gè)服務(wù)器進(jìn)行并發(fā)通信。
(4)命名管道可以用于網(wǎng)絡(luò )間兩個(gè)進(jìn)程的通信,而其實(shí)現的過(guò)程與本地進(jìn)程通信完全一致。
實(shí)驗目標:在客戶(hù)端輸入數據a和b,然后發(fā)送到服務(wù)器并計算a+b,然后把計算結果發(fā)送到客戶(hù)端??梢远鄠€(gè)客戶(hù)端與同一個(gè)服務(wù)器并行通信。
界面設計:
 
 
難點(diǎn)所在:
實(shí)現的過(guò)程比較簡(jiǎn)單,但有一個(gè)難點(diǎn)。原本當服務(wù)端使用ConnectNamedPipe函數后,如果有客戶(hù)端連接,就可以直接進(jìn)行交互。原來(lái)我在實(shí)現過(guò)程中,當管道空閑時(shí),管道的線(xiàn)程函數會(huì )無(wú)限(INFINITE)阻塞。若現在需要停止服務(wù),就必須結束所有的線(xiàn)程,TernimateThread可以作為一個(gè)結束線(xiàn)程的方法,但我基本不用這個(gè)函數。一旦使用這個(gè)函數之后,目標線(xiàn)程就會(huì )立即結束,但如果此時(shí)的目標線(xiàn)程正在操作互斥資源、內核調用、或者是操作共享DLL的全局變量,可能會(huì )出現互斥資源無(wú)法釋放、內核異常等現象。這里我用重疊I/0來(lái)解決這個(gè)問(wèn)題,在創(chuàng )建PIPE時(shí)使用FILE_FLAG_OVERLAPPED標志,這樣使用ConnectNamedPipe后會(huì )立即返回,但線(xiàn)程的阻塞由等待函數WaitForSingleObject來(lái)實(shí)現,等待OVERLAPPED結構的事件對象被設置。
客戶(hù)端主要代碼:
代碼:
void CMyDlg::OnSubmit()  {   // 打開(kāi)管道   HANDLE hPipe = CreateFile("\\\\.\\Pipe\\NamedPipe", GENERIC_READ | GENERIC_WRITE,      0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL) ;   if ( hPipe == INVALID_HANDLE_VALUE )   {     this->MessageBox ( "打開(kāi)管道失敗,服務(wù)器尚未啟動(dòng),或者客戶(hù)端數量過(guò)多" ) ;     return ;   }   DWORD nReadByte, nWriteByte ;   char szBuf[1024] = {0} ;   // 把兩個(gè)整數(a,b)格式化為字符串   sprintf ( szBuf, "%d %d", this->nFirst, this->nSecond ) ;   // 把數據寫(xiě)入管道   WriteFile ( hPipe, szBuf, strlen(szBuf), &nWriteByte, NULL ) ;   memset ( szBuf, 0, sizeof(szBuf) ) ;   // 讀取服務(wù)器的反饋信息   ReadFile ( hPipe, szBuf, 1024, &nReadByte, NULL ) ;   // 把返回信息格式化為整數   sscanf ( szBuf, "%d", &(this->nResValue) ) ;   this->UpdateData ( false ) ;   CloseHandle ( hPipe ) ; }

服務(wù)端主要代碼:
代碼:
// 啟動(dòng)服務(wù) void CMyDlg::OnStart()  {   CString lpPipeName = "\\\\.\\Pipe\\NamedPipe" ;   for ( UINT i = 0; i  MessageBox ( "創(chuàng )建管道錯誤!" ) ;       return ;     }     // 為每個(gè)管道實(shí)例創(chuàng )建一個(gè)事件對象,用于實(shí)現重疊IO     PipeInst[i].hEvent  =  CreateEvent ( NULL, false, false, false ) ;     // 為每個(gè)管道實(shí)例分配一個(gè)線(xiàn)程,用于響應客戶(hù)端的請求     PipeInst[i].hTread = AfxBeginThread ( ServerThread, &PipeInst[i], THREAD_PRIORITY_NORMAL ) ;   }      this->SetWindowText ( "命名管道實(shí)例之服務(wù)器(運行)" ) ;   this->MessageBox ( "服務(wù)啟動(dòng)成功" ) ; } // 停止服務(wù) void CMyDlg::OnStop()  {   DWORD dwNewMode = PIPE_TYPE_BYTE|PIPE_READMODE_BYTE|PIPE_NOWAIT ;   for ( UINT i = 0; i  SetWindowText ( "命名管道實(shí)例之服務(wù)器" ) ;   this->MessageBox ( "停止啟動(dòng)成功" ) ; } // 線(xiàn)程服務(wù)函數 UINT ServerThread ( LPVOID lpParameter ) {   DWORD  nReadByte = 0, nWriteByte = 0, dwByte = 0 ;     char  szBuf[MAX_BUFFER_SIZE] = {0} ;   PIPE_INSTRUCT  CurPipeInst = *(PIPE_INSTRUCT*)lpParameter ;   OVERLAPPED OverLapStruct = { 0, 0, 0, 0, CurPipeInst.hEvent } ;   while ( true )   {     memset ( szBuf, 0, sizeof(szBuf) ) ;       // 命名管道的連接函數,等待客戶(hù)端的連接(只針對NT)     ConnectNamedPipe ( CurPipeInst.hPipe, &OverLapStruct ) ;     // 實(shí)現重疊I/0,等待OVERLAPPED結構的事件對象     WaitForSingleObject ( CurPipeInst.hEvent, INFINITE ) ;     // 檢測I/0是否已經(jīng)完成,如果未完成,意味著(zhù)該事件對象是人工設置,即服務(wù)需要停止     if ( !GetOverlappedResult ( CurPipeInst.hPipe, &OverLapStruct, &dwByte, true ) )       break ;     // 從管道中讀取客戶(hù)端的請求信息     if ( !ReadFile ( CurPipeInst.hPipe, szBuf, MAX_BUFFER_SIZE, &nReadByte, NULL ) )     {       MessageBox ( 0, "讀取管道錯誤!", 0, 0 ) ;       break ;     }          int a, b ;     sscanf ( szBuf, "%d %d", &a, &b ) ;     pMyDlg->nFirst    = a ;     pMyDlg->nSecond    = b ;     pMyDlg->nResValue  = a + b ;     memset ( szBuf, 0, sizeof(szBuf) ) ;     sprintf ( szBuf, "%d", pMyDlg->nResValue ) ;     // 把反饋信息寫(xiě)入管道     WriteFile ( CurPipeInst.hPipe, szBuf, strlen(szBuf), &nWriteByte, NULL ) ;     pMyDlg->SetDlgItemInt ( IDC_FIRST, a, true ) ;     pMyDlg->SetDlgItemInt ( IDC_SECOND, b, true ) ;     pMyDlg->SetDlgItemInt ( IDC_RESULT, pMyDlg->nResValue, true ) ;     // 斷開(kāi)客戶(hù)端的連接,以便等待下一客戶(hù)的到來(lái)     DisconnectNamedPipe ( CurPipeInst.hPipe ) ;   }   return 0 ; }
HOHO....學(xué)完之后提點(diǎn)建議
 

  LPTSTR lpProgram = new char( sizeof(argv[1]) ) ;
  strcpy ( lpProgram, argv[1] ) ;
  LPTSTR lpInputFile = new char( sizeof(argv[2]) ) ;
  strcpy ( lpInputFile, argv[2] ) ;
  LPTSTR lpOutputFile = new char( sizeof(argv[3]) ) ;
  strcpy ( lpOutputFile, argv[3] ) ;    

這段內存沒(méi)有被釋放,另外這個(gè)寫(xiě)法好像也有點(diǎn)問(wèn)題(雖然可以正常運行),不知這樣改一下如何:
  LPTSTR lpProgram = new char[ sizeof(argv[1]) ] ;
  strcpy ( lpProgram, argv[1] ) ;
  LPTSTR lpInputFile = new char[ sizeof(argv[2]) ] ;
  strcpy ( lpInputFile, argv[2] ) ;
  LPTSTR lpOutputFile = new char[ sizeof(argv[3]) ] ;
  strcpy ( lpOutputFile, argv[3] ) ;    

吹毛求疵之舉,兄弟不要見(jiàn)怪
 
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
linux進(jìn)程間通信方式之匿名管道
12個(gè)有趣的C語(yǔ)言面試題
Linux——多進(jìn)程服務(wù)器與客戶(hù)端并發(fā)通信
Linux系統編程 | 共享內存之mmap
UNIX 編程資料 (轉)
Linux系統編程之進(jìn)程間通信方式:命名管道(二)
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久