網(wǎng)站開發(fā)技術(shù)實(shí)驗(yàn)報(bào)告主流搜索引擎有哪些
一: 簡(jiǎn)介
在類linux系統(tǒng)中管道分為有名管道和匿名管道。兩者都能單方向的跨進(jìn)程通信。
- 匿名管道(
pipe
): 必須是父子進(jìn)程之間,而且子進(jìn)程只能由父進(jìn)程fork() 出來(lái)的,才能繼承父進(jìn)程的管道句柄,一般mac 開發(fā)用的很少。 - 有名管道(
fifo
)又叫命名管道: 可以在同一臺(tái)機(jī)器,沒有關(guān)系的進(jìn)程間通信。 其本質(zhì)是本地創(chuàng)建一個(gè)文件,然后使用其路徑作為紐帶。open
后再內(nèi)核空間產(chǎn)生管道,不同進(jìn)程之間分別連接管道的讀和寫的端口進(jìn)行通信。
這里主要針對(duì)有名管道
進(jìn)行研究。
二:主要函數(shù)
以下函數(shù)在macOS
和 Linux
下均適用。 Windows
不行,其創(chuàng)建的關(guān)鍵函數(shù)是:CreateNamedPipe(...)
1. int mkfifo(const char *, mode_t);
第一個(gè)參數(shù)是路徑,可以放在tmp
路徑下,比如const char *fifoName = "/tmp/com.jimbo.fifo";
mode_t
代表賦予的權(quán)限,測(cè)試用0777
就可以了。
運(yùn)行 ls -la /tmp/
下,明顯存在我們創(chuàng)建的管道文件。
有名管道會(huì)在 在第一列將會(huì)顯示類型 s
這里還有其他類型的文件。其中p
表示命名管道文件,d
表示目錄文件,l
表示符號(hào)連接文件,-
表示普通文件,s
表示socket文件,c
表示字符設(shè)備文件,b
表示塊設(shè)備文件。
2. int open(const char *, int, ...)
- 返回值為,打開的管道的操作句柄,讀寫都需要它
- 第一個(gè)參數(shù)是路徑,同上
- 第二個(gè)參數(shù)為打開模式:
#define O_RDONLY 0x0000 /* open for reading only */ 只讀
#define O_WRONLY 0x0001 /* open for writing only */ 只寫
#define O_NONBLOCK 0x00000004 /* no delay */ 不阻塞
...
demo主要使用上面三種模式,
- 發(fā)送端使用
O_WRONLY
- 接收端使用
O_WRONLY
O_NONBLOCK
代表open文件的時(shí)候,這個(gè)方法是否需要阻塞,默認(rèn)不傳是阻塞的.
3. ssize_t read(int, void *, size_t)
往管道讀取數(shù)據(jù)。常規(guī)操作,傳入open
后的返回句柄,和字符串地址和最大長(zhǎng)度
4. ssize_t write(int __fd, const void * __buf, size_t __nbyte)
往管道寫入數(shù)據(jù)。常規(guī)操作,傳入open
后的返回句柄,和字符串地址和字符串長(zhǎng)度
三:demo代碼
如下圖,創(chuàng)建了兩個(gè)app,分別為發(fā)送端(寫數(shù)據(jù))和接收端(讀數(shù)據(jù))。
macOS App 來(lái)說(shuō)貌似需要雙方都是 非沙盒的才行。 不然文件訪問不了。
1. 發(fā)送端主要邏輯
-
主要?jiǎng)?chuàng)建了
mkfifo
一個(gè)管道 -
創(chuàng)建了子進(jìn)程
-
open()
阻塞式的等子進(jìn)程打開管道文件 -
上一步阻塞過了后,點(diǎn)擊
writeMsg
往管道中寫入消息。
主要代碼: ViewController.mm
文件代碼
//發(fā)送端
#import "ViewController.h"
#include <sys/unistd.h>
#include <sys/stat.h>static const char *fifoName = "/tmp/com.jimbo.fifo";@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];[self.view.window setTitle:@"Main window"];int ret = 0;if (access(fifoName, F_OK) == -1) {//管道不存在,創(chuàng)建一個(gè)新的ret = mkfifo(fifoName, 0777);if (ret != 0) {NSLog(@"mkfifo failed! ret:%i", ret);return;}}//啟動(dòng)子進(jìn)程NSString *subAppp = [[NSBundle mainBundle] pathForResource:@"PipeApp_Sub" ofType:@"app"];subAppp = [NSString stringWithFormat:@"%@/Contents/MacOS/PipeApp_Sub", subAppp];NSTask *task = [[NSTask alloc] init];[task setLaunchPath:subAppp];NSError *error;[task launchAndReturnError:&error];//阻塞監(jiān)聽子進(jìn)程打開 讀端。self.writePipeID = open(fifoName,O_WRONLY);printf("open fd:%i\n", self.writePipeID);if(self.writePipeID<0){perror("writer open err");return ;}
}- (IBAction)writeMsg:(id)sender {//往管道發(fā)送消息,消息為ui的文本框的數(shù)據(jù)const char *text = [self.textLabel.stringValue UTF8String];ssize_t writeSize = write(self.writePipeID, text, strlen(text)+1);NSLog(@"write succed size:%zi", writeSize);
}
2. 接收端主要邏輯
-
收到非阻塞的
O_NONBLOCK
打開只讀管道,(打開后發(fā)送端的阻塞會(huì)通過) -
等到發(fā)送端發(fā)送了數(shù)據(jù)后。。。
-
點(diǎn)擊接收數(shù)據(jù)的按鈕
receiveMsg
,read()
函數(shù)讀取管道中的數(shù)據(jù),并顯示在ui的textView
中
//接收端
#import "ViewController.h"
#include <sys/stat.h>@interface ViewController()
@property (nonatomic, assign) int pipeReadID;
@property (unsafe_unretained) IBOutlet NSTextView *textView;@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];const char *fifoName = "/tmp/com.jimbo.fifo";// 由于是ui 主線程,所以選擇了 非阻塞式的打開 管道self.pipeReadID = open(fifoName, O_RDONLY | O_NONBLOCK);if (self.pipeReadID < 0) {NSLog(@"open 失敗了");self.textView.string = @"open 失敗了";} else {self.textView.string = @"點(diǎn)擊接收按鈕,接收數(shù)據(jù)";}
}- (IBAction)receiveMsg:(id)sender {size_t n;char line[PIPE_BUF+1];n = read(self.pipeReadID, line, PIPE_BUF);NSLog(@"count:%zu get msg: %s", n ,line);if (n > PIPE_BUF || n < 0) {return;}self.textView.string = [NSString stringWithFormat:@"收到的數(shù)據(jù):%@", [[NSString alloc] initWithBytes:line length:n encoding:NSUTF8StringEncoding]];
}- (void)dealloc {close(self.pipeReadID);
}@end