iOS リバース エンジニアリング: iOS プロセス間通信ソリューションの詳細な調査とローカル ソケットの紹介

モバイル アプリケーション開発において、プロセス間通信 (IPC) は、異なるアプリケーション間のコラボレーションとデータ共有のための重要なテクノロジです。iOS エコシステムではプロセスとスレッドが基本概念であり、プロセス間通信ソリューションはアプリケーションの機能拡張やパフォーマンスの最適化を強力にサポートします。

1. プロセスとスレッド: オペレーティング システムの中核概念

プロセスとは、オペレーティング システムで実行される独立したプログラム インスタンスを指します。各プロセスには独立したメモリ空間があり、データの分離と異なるプロセス間の通信には特定のメカニズムが必要です。iOS では、各アプリケーションは独立したプロセスで実行されるため、アプリケーション間の分離と安定性が確保されます。

スレッドはプロセス内の実行単位であり、プロセスには複数のスレッドを含めることができます。スレッドはプロセスのメモリ空間を共有するため、データをより簡単に共有できます。ただし、マルチスレッド プログラミングは、スレッドの同期や競合状態などの複雑な問題も引き起こします。iOS では通常、メイン スレッドが UI の対話を処理し、バックグラウンド スレッドが時間のかかるタスクを実行してユーザー インターフェイスの応答性を維持します。

コードの観点からプロセスがどのように作成されるかについて説明します。

1.1 Linuxでのプロセスの作成

Linux では、C 言語のシステム コールを使用して新しいプロセスを作成できます。このうち、fork() はよく使われるシステムコールで、親プロセスと子プロセスを並行して実行できるように新しいプロセスを作成するために使用されます。以下は、C 言語を使用して Linux でプロセスを作成する方法を示す簡単なサンプル コードです。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int main() {
    
    
    pid_t child_pid;

    // 创建新进程
    child_pid = fork();

    if (child_pid < 0) {
    
    
        fprintf(stderr, "Fork failed\n");
        return 1;
    } else if (child_pid == 0) {
    
    
        // 子进程执行的代码
        printf("This is the child process. PID: %d\n", getpid());
        // 子进程退出
        exit(0);
    } else {
    
    
        // 父进程执行的代码
        printf("This is the parent process. Child PID: %d\n", child_pid);
        // 等待子进程结束
        wait(NULL);
        printf("Child process has terminated.\n");
    }

    return 0;
}

この例では、fork() は新しいプロセスを作成し、子プロセスは fork() が戻った場所から実行を開始します。子プロセスでは、子プロセスの PID を出力し、exit(0) を使用して子プロセスを終了します。親プロセスでは、子プロセスの PID を出力し、wait(NULL) を使用して子プロセスが終了するのを待ちます。親プロセスと子プロセスはメモリ空間上では独立していますが、ファイル記述子などのリソースを共有することに注意してください。

1.2 iOS で上記のコードをコンパイルして実行する

iOS プラットフォームでは、iOS アプリケーションはサンドボックス環境で実行され、プロセスの管理と作成にいくつかの制限があるため、fork() を直接使用してプロセスを作成することはできません。iOS では、プロセスの作成と管理はシステムによって制御され、通常はアプリケーションのメイン スレッドによって開始されます。通常どおりコンパイルして実行できますが、fork() 関数を呼び出そうとするとアプリケーションがクラッシュします。

1.3 fork() の基本原理

ここに画像の説明を挿入します

プロセス間通信をより深く理解するために、fork() が呼び出されたときにオペレーティング システムの下部でどのような変化が起こるかを紹介しましょう。

プロセスのコピー:プロセスが fork() を呼び出すと、オペレーティング システムは子プロセスと呼ばれる新しいプロセスを作成します。子プロセスは、親プロセスのすべてのメモリ、ファイル記述子、およびその他のリソースを含む親プロセスのコピーです。
メモリ空間のコピー:子プロセスのアドレス空間は親プロセスと同じですが、子プロセスは独立したコピーを取得します。これは、「コピーオンライト」メカニズムによって実現されます。これは、親プロセスと子プロセスが最初はメモリを共有しますが、いずれかのプロセスがメモリの内容を変更すると、オペレーティング システムが変更された部分の新しいコピーを作成することを意味します。
プロセス ID の割り当て:オペレーティング システムは、子プロセスに一意のプロセス識別子 (PID) を割り当てます。子プロセスの PID は親プロセスとは異なりますが、他の属性 (UID、GID など) は一貫したままである可​​能性があります。
ファイル記述子の処理:子プロセスは親プロセスのファイル記述子を継承します。ファイル記述子は、ファイルやソケットなどの I/O リソースにアクセスするために使用されるハンドルです。子プロセスは、ファイル記述子を継承した後、同じファイルまたはネットワーク接続を共有できます。
戻り値:親プロセスでは、fork() 関数は子プロセスの PID (正の整数) を返します。子プロセスでは、fork() 関数は 0 を返します。fork() が失敗した場合、戻り値は負の数になり、子プロセスの作成が失敗したことを示します。
実行を継続する:親プロセスと子プロセスは両方とも、fork() 呼び出し後の場所から実行を継続します。子プロセスは親プロセスのコピーであるため、両方とも同じコードの場所から実行を開始します。

その中でも特に注目したいのが、大規模工場の面接でよく取り上げられる「書きながらコピー」というコンセプトですので、興味のある方は後ほど紹介しますので、このコラムをフォローして最新情報を入手してください。記事。

2. iOSにおけるプロセス間通信ソリューション

iOS では、異なるアプリケーション間のデータ共有と通信には、特定のプロセス間通信スキームを使用する必要があります。一般的な iOS プロセス間通信方法をいくつか示します。

**URL スキーム:** アプリケーションはカスタマイズされた URL スキームを登録し、他のアプリケーションの URL を介してターゲット アプリケーションを呼び出し、データを転送できます。これは通常、単純なアプリケーションのジャンプとデータ共有に使用されます。
アプリ グループ:アプリ グループを使用すると、さまざまなアプリが、環境設定やファイルなどの共有データを保存するための同じコンテナ ディレクトリのセットを共有できます。
キーチェーンの共有:キーチェーンは機密データの保存に使用される安全なコンテナであり、アプリケーションは開発者アカウントでキーチェーン データを共有し、アプリケーション間のデータ共有を実現できます。
通知:アプリは通知センターを使用して通知を送受信し、アプリ間のメッセージングを実装できます。これは、1 対多の通信シナリオに適しています。
ローカル ソケット: iOS プロセスはローカル ソケットを介して通信することもできます。これはより一般的な方法です。以下で詳しく紹介します。

3. プロセス間通信にローカルソケットを使用する

ローカル ソケットは、ネットワーク ソケットに基づくプロセス間通信方法であり、同じデバイス上の異なるプロセス間の通信接続を確立するのに適しています。Local Socket を使用したプロセス間通信の簡単なコード例を次に示します。

プロセス1 – データの送信

import Foundation

let serverURL = URL(fileURLWithPath: "/path/to/socket")
let socket = try! Socket.create(family: .unix, type: .stream, proto: .unix)
try! socket.connect(to: serverURL)

let dataToSend = "Hello, Process 2!".data(using: .utf8)!
try! socket.write(from: dataToSend)
socket.close()

プロセス 2 - データの受信

import Foundation

let serverURL = URL(fileURLWithPath: "/path/to/socket")
let socket = try! Socket.create(family: .unix, type: .stream, proto: .unix)
try! socket.bind(to: serverURL)
try! socket.listen(maxBacklogSize: 1)

let clientSocket = try! socket.acceptClientConnection()

var receivedData = Data()
_ = try! clientSocket.read(into: &receivedData)
let receivedString = String(data: receivedData, encoding: .utf8)
print("Received data: \(receivedString ?? "")")
clientSocket.close()

iOS のプロセス間通信ソリューションには、さまざまなシナリオでさまざまな利点と用途があります。アプリケーション間のデータ共有とコラボレーションを実現し、ユーザーにより良いエクスペリエンスを提供するには、実際のニーズに基づいて適切な通信方法を選択する必要があります。

おすすめ

転載: blog.csdn.net/zh405123507/article/details/132600899