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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

说说I/O与IPC

發布時間:2023/12/19 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 说说I/O与IPC 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
程間通信IPC,也就是Inter-Process Communication的縮寫。一個進程其實就是一個狹義上的程序。


廣義上:一個服務器也就是一個進程。比如客戶端和服務器的連接就是兩個進程在通信,只是這兩個進程并不在同一臺計算機上,它們進程間的通信方式就是我們非常熟悉的sockt接口,更下層一些可能就是TCP/IP協議。這樣進程與進程間通信就組成了更大的一個系統,也就是說,在網絡系統上,我們需要進程通信完成協作任務或者交互任務。比如P2P的軟件就是兩個不同計算機的程序進行數據交互,從而完成下載或通信的任務。


狹義上:我們一臺主機上需要兩個進程共享數據,如:我們需要打開另一個進程保存的文件,我們有時候需要訪問正在運行的另外進程的數據對象或者通知另外進程具體完成任務等。

進程由于是內核(OS kernel)的功能,因此進程的創建和通信其實和各種OS緊密相關的。當然現在OS在架構上有很多思想是想通的,所以進程間通信在各種操作系統上有不同也有相同的地方。如window和Linux有很多類似的地方,也有較多的區別,Android系統也提供自己的IPC機制,iOS也有自己的類似的IPC機制。

另外,當前很多語言和框架(Framework)為了實現跨平臺性,都封裝了進程的操作,將線程的使用提高到了語言的層面。而不用developer再去進行系統調用(或系統API)來操作進程了。比如Java語言,進程和線程就是其語言提供的。再比如QT框架,也提供了進程線程的操作,彌補了C/C++語言上沒有提供進程線程的遺憾。我們這里還是有必要了解下各個OS在系統調用層次的進程操作。


一. 在Windows OS上,有幾種常用的進程間通信方式:
1 .文件映射
文件映射(Memory-Mapped Files)能使進程把文件內容當作進程地址區間一塊內存那樣來對待。因此,進程不必使用文件I/O操作,只需簡單的指針操作就可讀取和修改文件的內容。
Win32 API允許多個進程訪問同一文件映射對象,各個進程在它自己的地址空間里接收內存的指針。通過使用這些指針,不同進程就可以讀或修改文件的內容,實現了對文件中數據的共享。
應用程序有三種方法來使多個進程共享一個文件映射對象。
(1)繼承:第一個進程建立文件映射對象,它的子進程繼承該對象的句柄。
(2)命名文件映射:第一個進程在建立文件映射對象時可以給該對象指定一個名字(可與文件名不同)。第二個進程可通過這個名字打開此文件映射對象。另外,第一個進程也可以通過一些其它IPC機制(有名管道、郵件槽等)把名字傳給第二個進程。
(3)句柄復制:第一個進程建立文件映射對象,然后通過其它IPC機制(有名管道、郵件槽等)把對象句柄傳遞給第二個進程。第二個進程復制該句柄就取得對該文件映射對象的訪問權限。
文件映射是在多個進程間共享數據的非常有效方法,有較好的安全性。但文件映射只能用于本地機器的進程之間,不能用于網絡中,而開發者還必須控制進程間的同步。

2. 共享內存
Win32 API中共享內存(Shared Memory)實際就是文件映射的一種特殊情況。進程在創建文件映射對象時用0xFFFFFFFF來代替文件句柄(HANDLE),就表示了對應的文件映射對象是從操作系統頁面文件訪問內存,其它進程打開該文件映射對象就可以訪問該內存塊。由于共享內存是用文件映射實現的,所以它也有較好的安全性,也只能運行于同一計算機上的進程之間。

3. 匿名管道
管道(Pipe)是一種具有兩個端點的通信通道:有一端句柄的進程可以和有另一端句柄的進程通信。管道可以是單向-一端是只讀的,另一端點是只寫的;也可以是雙向的一管道的兩端點既可讀也可寫。
匿名管道(Anonymous Pipe)是 在父進程和子進程之間,或同一父進程的兩個子進程之間傳輸數據的無名字的單向管道。通常由父進程創建管道,然后由要通信的子進程繼承通道的讀端點句柄或寫 端點句柄,然后實現通信。父進程還可以建立兩個或更多個繼承匿名管道讀和寫句柄的子進程。這些子進程可以使用管道直接通信,不需要通過父進程。
匿名管道是單機上實現子進程標準I/O重定向的有效方法,它不能在網上使用,也不能用于兩個不相關的進程之間。
4 .命名管道
命名管道(Named Pipe)是服務器進程和一個或多個客戶進程之間通信的單向或雙向管道。不同于匿名管道的是命名管道可以在不相關的進程之間和不同計算機之間使用,服務器建立命名管道時給它指定一個名字,任何進程都可以通過該名字打開管道的另一端,根據給定的權限和服務器進程通信。
命名管道提供了相對簡單的編程接口,使通過網絡傳輸數據并不比同一計算機上兩進程之間通信更困難,不過如果要同時和多個進程通信它就力不從心了。

5. 動態連接庫
Win32動態連接庫(DLL)中的全局數據可以被調用DLL的所有進程共享,這就又給進程間通信開辟了一條新的途徑,當然訪問時要注意同步問題。雖然可以通過DLL進行進程間數據共享,但從數據安全的角度考慮,我們并不提倡這種方法,使用帶有訪問權限控制的共享內存的方法更好一些。
6 .遠程過程調用
Win32 API提供的遠程過程調用(RPC)使應用程序可以使用遠程調用函數,這使在網絡上用RPC進行進程通信就像函數調用那樣簡單。RPC既可以在單機不同進程間使用也可以在網絡中使用。
由于Win32 API提供的RPC服從OSF-DCE(Open Software Foundation Distributed Computing Environment)標準。所以通過Win32 API編寫的RPC應用程序能與其它操作系統上支持DEC的RPC應用程序通信。使用RPC開發者可以建立高性能、緊密耦合的分布式應用程序。
7 .Sockets
Windows Sockets規范是以U.C.Berkeley大學BSD UNIX中流行的Socket接口為范例定義的一套Windows下的網絡編程接口。除了Berkeley Socket原有的庫函數以外,還擴展了一組針對Windows的函數,使程序員可以充分利用Windows的消息機制進行編程。
現在通過Sockets實現進程通信的網絡應用越來越多,這主要的原因是Sockets的跨平臺性要比其它IPC機制好得多,另外WinSock 2.0不僅支持TCP/IP協議,而且還支持其它協議(如IPX)。Sockets的唯一缺點是它支持的是底層通信操作,這使得在單機的進程間進行簡單數據傳遞不太方便,這時使用下面將介紹的WM_COPYDATA消息將更合適些。
8 .WM_COPYDATA消息
WM_COPYDATA是一種非常強大卻鮮為人知的消息。當一個應用向另一個應用傳送數據時,發送方只需使用調用SendMessage函數,參數是目的窗口的句柄、傳遞數據的起始地址、WM_COPYDATA消息。接收方只需像處理其它消息那樣處理WM_COPY DATA消息,這樣收發雙方就實現了數據共享。
WM_COPYDATA是一種非常簡單的方法,它在底層實際上是通過文件映射來實現的。它的缺點是靈活性不高,并且它只能用于Windows平臺的單機環境下。

下面是c實現socket UDP,TCP傳輸數據:

tcp server:

#include "stdafx.h" #include <stdio.h> #include <winsock2.h> #pragma comment(lib,"ws2_32.lib") int main(int argc, char* argv[]) { //初始化WSA WORD sockVersion = MAKEWORD(2,2); WSADATA wsaData; if(WSAStartup(sockVersion, &wsaData)!=0) { return 0; } //創建套接字 SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(slisten == INVALID_SOCKET) { printf("socket error !"); return 0; } //綁定IP和端口 sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons(8888); sin.sin_addr.S_un.S_addr = INADDR_ANY; if(bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR) { printf("bind error !"); } //開始監聽 if(listen(slisten, 5) == SOCKET_ERROR) { printf("listen error !"); return 0; } //循環接收數據 SOCKET sClient; sockaddr_in remoteAddr; int nAddrlen = sizeof(remoteAddr); char revData[255]; while (true) { printf("等待連接...\n"); sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen); if(sClient == INVALID_SOCKET) { printf("accept error !"); continue; } printf("接受到一個連接:%s \r\n", inet_ntoa(remoteAddr.sin_addr)); //接收數據 int ret = recv(sClient, revData, 255, 0); if(ret > 0) { revData[ret] = 0x00; printf(revData); } //發送數據 char * sendData = "你好,TCP客戶端!\n"; send(sClient, sendData, strlen(sendData), 0); closesocket(sClient); } closesocket(slisten); WSACleanup(); return 0; } tcp client:

#include "stdafx.h" #include <WINSOCK2.H> #include <STDIO.H> #pragma comment(lib,"ws2_32.lib") int main(int argc, char* argv[]) { WORD sockVersion = MAKEWORD(2,2); WSADATA data; if(WSAStartup(sockVersion, &data) != 0) { return 0; } SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(sclient == INVALID_SOCKET) { printf("invalid socket !"); return 0; } sockaddr_in serAddr; serAddr.sin_family = AF_INET; serAddr.sin_port = htons(8888); serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); if (connect(sclient, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR) { printf("connect error !"); closesocket(sclient); return 0; } char * sendData = "你好,TCP服務端,我是客戶端!\n"; send(sclient, sendData, strlen(sendData), 0); char recData[255]; int ret = recv(sclient, recData, 255, 0); if(ret > 0) { recData[ret] = 0x00; printf(recData); } closesocket(sclient); WSACleanup(); return 0; }
UDP server:

#include "stdafx.h" #include <stdio.h> #include <winsock2.h> #pragma comment(lib, "ws2_32.lib") int main(int argc, char* argv[]) { WSADATA wsaData; WORD sockVersion = MAKEWORD(2,2); if(WSAStartup(sockVersion, &wsaData) != 0) { return 0; } SOCKET serSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if(serSocket == INVALID_SOCKET) { printf("socket error !"); return 0; } sockaddr_in serAddr; serAddr.sin_family = AF_INET; serAddr.sin_port = htons(8888); serAddr.sin_addr.S_un.S_addr = INADDR_ANY; if(bind(serSocket, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR) { printf("bind error !"); closesocket(serSocket); return 0; } sockaddr_in remoteAddr; int nAddrLen = sizeof(remoteAddr); while (true) { char recvData[255]; int ret = recvfrom(serSocket, recvData, 255, 0, (sockaddr *)&remoteAddr, &nAddrLen); if (ret > 0) { recvData[ret] = 0x00; printf("接受到一個連接:%s \r\n", inet_ntoa(remoteAddr.sin_addr)); printf(recvData); } char * sendData = "一個來自服務端的UDP數據包\n"; sendto(serSocket, sendData, strlen(sendData), 0, (sockaddr *)&remoteAddr, nAddrLen); } closesocket(serSocket); WSACleanup(); return 0; } UDP client:

#include "stdafx.h" #include <stdio.h> #include <winsock2.h> #pragma comment(lib, "ws2_32.lib") int main(int argc, char* argv[]) { WORD socketVersion = MAKEWORD(2,2); WSADATA wsaData; if(WSAStartup(socketVersion, &wsaData) != 0) { return 0; } SOCKET sclient = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons(8888); sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); int len = sizeof(sin); char * sendData = "來自客戶端的數據包.\n"; sendto(sclient, sendData, strlen(sendData), 0, (sockaddr *)&sin, len); char recvData[255]; int ret = recvfrom(sclient, recvData, 255, 0, (sockaddr *)&sin, &len); if(ret > 0) { recvData[ret] = 0x00; printf(recvData); } closesocket(sclient); WSACleanup(); return 0; }

系統監聽端口的方式就是socket實現。如果深入了解系統的socket機制,閱讀《操作系統源碼解讀 reactOS》-- 毛德操。

上面的IPC通信中的文件讀寫和網絡交互數據讀寫就是I/O部分。

二. Linux下進程間通信的幾種主要手段簡介:
管道(Pipe)及有名管道(named pipe):管道可用于具有親緣關系進程間的通信,有名管道克服了管道沒有名字的限制,因此,除具有管道所具有的功能外,它還允許無親緣關系進程間的通信;
信號(Signal):信號是比較復雜的通信方式,用于通知接受進程有某種事件發生,除了用于進程間通信外,進程還可以發送信號給進程本身;linux除了支持Unix早期信號語義函數sigal外,還支持語義符合Posix.1標準的信號函數sigaction(實際上,該函數是基于BSD的,BSD為了實現可靠信號機制,又能夠統一對外接口,用sigaction函數重新實現了signal函數);
報文(Message)隊列(消息隊列):消息隊列是消息的鏈接表,包括Posix消息隊列system V消息隊列。有足夠權限的進程可以向隊列中添加消息,被賦予讀權限的進程則可以讀走隊列中的消息。消息隊列克服了信號承載信息量少,管道只能承載無格式字節流以及緩沖區大小受限等缺點。
共享內存:使得多個進程可以訪問同一塊內存空間,是最快的可用IPC形式。是針對其他通信機制運行效率較低而設計的。往往與其它通信機制,如信號量結合使用,來達到進程間的同步及互斥。
信號量(semaphore):主要作為進程間以及同一進程不同線程之間的同步手段。
套接口(Socket):更為一般的進程間通信機制,可用于不同機器之間的進程間通信。起初是由Unix系統的BSD分支開發出來的,但現在一般可以移植到其它類Unix系統上:Linux和其變種都支持套接字。


三.Android 系統IPC

1.broadcast 廣播,Android 組件。

2.contentprovider Android組件。

3.socket 網絡交互。

4.binder機制,此機制基于管道,信號機制。

5.AIDL 機制,其實基于對象數據序列化的機制。


總結

以上是生活随笔為你收集整理的说说I/O与IPC的全部內容,希望文章能夠幫你解決所遇到的問題。

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