カーネルエクステンションへ移動
未分類 No Comments »お久しぶりです。
えー、Cocoaすっ飛ばします、申し訳ありません。
iPhone 3Gも出た事だし、多分その手の話は腐るほど出てくる事でしょう。
ここは一気に斜め45度に脇道、カーネルエクステンションについて色々と調べていこうと思います。
Cocoaは簡単です。
Objective-Cの書式に慣れれば難しくありません。
後はライブラリの使い方だけです、複雑なGUIのアプリ作成は難しいけど。
では、乞うご期待と言う事で!
お久しぶりです。
えー、Cocoaすっ飛ばします、申し訳ありません。
iPhone 3Gも出た事だし、多分その手の話は腐るほど出てくる事でしょう。
ここは一気に斜め45度に脇道、カーネルエクステンションについて色々と調べていこうと思います。
Cocoaは簡単です。
Objective-Cの書式に慣れれば難しくありません。
後はライブラリの使い方だけです、複雑なGUIのアプリ作成は難しいけど。
では、乞うご期待と言う事で!
お次はクライアントの実装です。
サーバの実装と比べれば、とても簡単です。
const char *SOCK_NAME = "/tmp/socket";
int main (int argc, const char * argv[]) {
struct sockaddr_un addr;
int fd, ret;
char buf[1024];
// create socket.
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
perror("socket");
exit(1);
}
// initialize zero.
bzero((char *)&addr, sizeof(addr));
// insert socket name.
addr.sun_len = sizeof(addr);
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, SOCK_NAME);
// try connect server.
if (connect(fd, (struct sockaddr *)&addr, SUN_LEN(&addr)) < 0) {
perror("bind");
exit(1);
}
// send data.
while (fgets(buf, 1024, stdin)) {
write(fd, buf, 1024);
ret = read(fd, buf, ret);
printf("%s", buf);
}
close(fd);
return 0;
}
これで非常に簡単なプロセス間通信が実装できました。
次回はサーバおよびクライアントを、実際のアプリケーションに組み込んで、意味のあるIPCを実現する予定です。
ようやくCocoaが登場しますよ!
さっそく実装開始、まずはサーバ側のプログラムを作成する。
この手のコードは腐るほどやり尽くされているようで、ほぼ定型コードになっていますね。
しかし、さっそく引っかかった。
// insert socket name.
saddr.sun_family = AF_UNIX;
strcpy(saddr.sun_path, SOCK_NAME);
// avoid bind failure.
unlink(SOCK_NAME);
// bind socket address.
if (bind(fd1, (struct sockaddr *)&saddr,
sizeof(saddr.sun_family) + strlen(SOCK_NAME)) < 0){
perror("bind");
exit(1);
}
これだと、作成されるソケットファイル名の最後の一文字が脱落する。
まっさらな状態で実行すると問題ないが、2回目以降必ずbind()が失敗する。
何故だかわからない、事前にunlink()は呼んでるのに、2日ほど悩む。
そこで、アップルのサイトにあるサンプルコード「CFLocalServer」のソースを眺めたところ、すぐに答えが判明。
// insert socket name.
saddr.sun_len = sizeof(saddr);
saddr.sun_family = AF_UNIX;
strcpy(saddr.sun_path, SOCK_NAME);
// avoid bind failure.
unlink(SOCK_NAME);
// bind socket address.
if (bind(fd1, (struct sockaddr *)&saddr, SUN_LEN(&saddr)) < 0) {
perror("bind");
return 1;
}
まだまだ勉強が足りないですね。
以下、ソースコード全文です。
こちらの内容を参考にさせて頂きました。
const char *SOCK_NAME = "/tmp/socket";
int main (int argc, const char * argv[]) {
int i, ret;
int fd1, fd2;
unsigned int len;
char buf[1024];
struct sockaddr_un saddr;
struct sockaddr_un caddr;
// create socket.
if ((fd1 = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
perror("socket");
exit(1);
}
// initialize zero.
bzero((char *)&saddr, sizeof(saddr));
// insert socket name.
saddr.sun_len = sizeof(saddr);
saddr.sun_family = AF_UNIX;
strcpy(saddr.sun_path, SOCK_NAME);
// avoid bind failure.
unlink(SOCK_NAME);
// bind socket address.
if (bind(fd1, (struct sockaddr *)&saddr, SUN_LEN(&saddr)) < 0) {
perror("bind");
exit(1);
}
// listen socket.
if (listen(fd1, 1) < 0) {
perror("listen");
exit(1);
}
for(;;) {
len = sizeof(caddr);
/*
* The incoming connection from the client is accepted by accept().
* The descriptor of the socket connected with the client : when succeeding.
* It is returned to fd2. The communication becomes possible through this fd2.
* Because fd1 becomes unnecessary, it shuts with close().
*/
if ((fd2 = accept(fd1, (struct sockaddr *)&caddr, &len)) < 0) {
perror("accept");
exit(1);
}
close(fd1);
// receive data.
while (ret = read(fd2, buf, 1024)) {
// capital letter is converted into the small letter.
for (i=0; i< ret; i++) {
if (isalpha(buf[i]))
buf[i] = toupper(buf[i]);
}
// sent back to the client.
write(fd2, buf, 1024);
}
// close socket.
close(fd2);
}
return 0;
}
いきなり脱線です(笑)。
Cocoaでプロセス間通信を実現する際には、いくつかの方法があるみたいです。
パイプに共有メモリ、Apple EventsにDistributed Notifications、Distributed Objects for Cocoa、もっと下回りまで行くとMach MessagingにBSD Notifications、Kernel Eventsと、多種多様な方法があるようです。
しかし、パイプ以外はかなり高度な内容みたいで、手っ取り早く実装するには向かなそうです。
パイプについては、NSPipeというそのまんまのクラスがあり、実に簡単にプロセス間通信を行う事ができました。
NSPipeについてはまたの機会と言う事にして、暫くはちょっとだけ高度?なUNIXドメインソケットによるプロセス間通信について追いかけようかと考えています。
今更ながら、ブログを始めます。
このブログでは、比率で言えば希少なMacプログラマーが日々格闘しているCocoaについて、やってる事を書こうと思います。
最近のアップルは景気が良いみたいで、Macも結構な勢いで売れており、Cocoaでもやってみるかーってな好奇心旺盛な方の手助けになれば幸いです。
たまにCocoa以外の事も書くつもりですが、どうぞお付き合い下さい。