프로세스 간 통신(IPC)

이 항목에서는 Windows 앱 SDK 데스크톱 앱과 다른 Win32 애플리케이션 간에 IPC(프로세스 간 통신)를 수행하는 다양한 방법을 설명합니다. Windows 앱 SDK 데스크톱 앱은 완전 신뢰 Win32 프로세스로 실행되므로 모든 OS 수준 IPC 메커니즘에 직접 액세스할 수 있습니다. 일부 메커니즘에는 아래 섹션에서 설명한 대로 앱이 MSIX로 패키지될 때 추가 요구 사항이 있습니다.

앱 서비스

앱 서비스를 사용하면 애플리케이션이 백그라운드에서 기본 형식(ValueSet)의 속성 모음을 수락하고 반환하는 서비스를 노출할 수 있습니다. 복합 개체는 직렬화된 경우 전달할 수 있습니다.

앱 서비스는 백그라운드 작업으로 처리되지 않거나 포그라운드 애플리케이션 내에서 처리 중일 수 있습니다.

메모

앱 서비스에는 패키지 ID가 있는 패키지된 앱이 필요합니다. MSIX 패키징을 사용하는 Windows 앱 SDK 앱에서 사용할 수 있습니다.

앱 서비스는 거의 실시간 대기 시간이 필요하지 않은 소량의 데이터를 공유하는 데 가장 적합합니다.

COM

COM 은 상호 작용하고 통신할 수 있는 이진 소프트웨어 구성 요소를 만들기 위한 분산 개체 지향 시스템입니다. 개발자는 COM을 사용하여 애플리케이션에 재사용 가능한 소프트웨어 구성 요소 및 자동화 계층을 만듭니다. COM 구성 요소는 프로세스 중이거나 처리되지 않을 수 있으며 클라이언트 및 서버 모델을 통해 통신할 수 있습니다. Out-of-process COM 서버는 오랫동안 개체 간 통신을 위한 수단으로 사용되어 왔습니다.

기능이 있는 runFullTrust 패키지된 애플리케이션은 패키지 매니페스트를 통해 IPC용 Out-of-process COM 서버를 등록할 수 있습니다. 이를 패키지된 COM이라고합니다.

Windows 앱 SDK 데스크톱 앱은 완전 신뢰 프로세스로 실행되므로 기존 Win32 애플리케이션과 마찬가지로 Windows 레지스트리를 통해 직접 COM 서버를 등록하고 사용할 수도 있습니다.

Filesystem

광범위한 파일 시스템 액세스

패키지된 애플리케이션은 broadFileSystemAccess 제한된 기능을 선언하여 광범위한 파일 시스템을 통해 IPC를 수행할 수 있습니다. 이 기능은 Windows.Storage API 및 Win32 FromApp API에 파일 시스템 전반에 대한 액세스 권한을 부여합니다.

기본적으로 패키지된 애플리케이션에 대한 파일 시스템을 통한 IPC는 이 섹션에 설명된 다른 메커니즘으로 제한됩니다.

게시자 캐시 폴더

PublisherCacheFolder를 사용하면 패키지된 애플리케이션이 동일한 게시자가 다른 패키지와 공유할 수 있는 폴더를 매니페스트에 선언할 수 있습니다.

공유 스토리지 폴더에는 다음과 같은 요구 사항 및 제한 사항이 있습니다.

  • 공유 스토리지 폴더의 데이터는 백업되거나 로밍되지 않습니다.
  • 사용자는 공유 스토리지 폴더의 내용을 지울 수 있습니다.
  • 공유 스토리지 폴더를 사용하여 다른 게시자의 애플리케이션 간에 데이터를 공유할 수 없습니다.
  • 공유 스토리지 폴더를 사용하여 다른 사용자 간에 데이터를 공유할 수 없습니다.
  • 공유 스토리지 폴더에는 버전 관리가 없습니다.

여러 애플리케이션을 게시하고 해당 애플리케이션 간에 데이터를 공유하는 간단한 메커니즘을 찾는 경우 PublisherCacheFolder는 간단한 파일 시스템 기반 옵션입니다.

파이프

파이프를 사용하면 파이프 서버와 하나 이상의 파이프 클라이언트 간에 간단한 통신이 가능합니다.

익명 파이프 및명명된 파이프는 다음 제약 조건으로 지원됩니다.

  • 기본적으로 패키지된 애플리케이션의 명명된 파이프는 프로세스가 완전 신뢰되지 않는 한 동일한 패키지 내의 프로세스 간에만 지원됩니다.
  • 명명된 개체를 공유하기 위한 지침에 따라 패키지 간에 명명된 파이프를 공유할 수 있습니다.
  • 패키지된 앱에서 명명된 파이프는 파이프 이름에 LOCAL\를 포함해야 합니다(예: \\.\pipe\LOCAL\<pipename>). 세그먼트는 LOCAL\ 파이프를 호출자의 로그인 세션으로 범위 지정하며 MSIX 패키지 앱에 필요합니다. NamedPipeServerStream와 같은 .NET API를 사용할 때는 LOCAL\<pipename> 부분만 전달하세요 — \\.\pipe\ 접두사는 내부적으로 처리됩니다.

Windows 앱 SDK 데스크톱 앱은 완전 신뢰 프로세스로 실행되므로 동일한 패키지 제한 없이 명명된 파이프를 만들고 사용할 수 있습니다. 그러나 완전 신뢰가 없는 다른 패키지된 앱과 통신하는 경우에도 위의 제약 조건이 적용됩니다.

명명된 파이프 예제(C#)

다음 예제에서는 명명된 전체 파이프 서버와 클라이언트를 두 개의 콘솔 애플리케이션으로 보여 줍니다. Windows 앱 SDK 데스크톱 앱은 완전 신뢰 프로세스이므로 명명된 파이프 IPC는 특별한 기능이나 매니페스트 항목 없이 작동합니다.

이 예제를 시도하려면 두 개의 콘솔 앱 프로젝트(사용하도록 설정된 대상 지정 net8.0-windowsImplicitUsings )를 만들고 서버를 먼저 실행한 다음 별도의 터미널에서 클라이언트를 실행합니다.

파이프 서버 — 명명된 파이프를 만들고 메시지를 그대로 클라이언트에 다시 보냅니다.

using System.Text;

string PipeName = @"LOCAL\WinAppSdkIpcDemo";

Console.WriteLine("Named Pipe Server");
Console.WriteLine($"  Process ID: {Environment.ProcessId}");
Console.WriteLine($"  User:       {Environment.UserName}");
Console.WriteLine($"  Pipe:       \\\\.\\pipe\\{PipeName}");
Console.WriteLine();

using var server = new System.IO.Pipes.NamedPipeServerStream(
    PipeName,
    System.IO.Pipes.PipeDirection.InOut,
    maxNumberOfServerInstances: 1,
    System.IO.Pipes.PipeTransmissionMode.Message,
    System.IO.Pipes.PipeOptions.Asynchronous);

Console.WriteLine("Waiting for client...");
await server.WaitForConnectionAsync();
Console.WriteLine("Client connected!");

byte[] buffer = new byte[4096];

while (server.IsConnected)
{
    try
    {
        int bytesRead = await server.ReadAsync(buffer);
        if (bytesRead == 0) break;

        string received = Encoding.UTF8.GetString(buffer, 0, bytesRead);
        Console.WriteLine($"  Received: \"{received}\"");

        if (received.Equals("QUIT", StringComparison.OrdinalIgnoreCase))
            break;

        // Echo the message back with the server's process ID
        string reply = $"Echo from PID {Environment.ProcessId}: {received}";
        await server.WriteAsync(Encoding.UTF8.GetBytes(reply));
        await server.FlushAsync();
    }
    catch (IOException)
    {
        break;
    }
}

Console.WriteLine("Done.");

파이프 클라이언트 - 서버에 연결하고 사용자 입력을 보냅니다.

using System.Text;

string PipeName = @"LOCAL\WinAppSdkIpcDemo";

Console.WriteLine("Named Pipe Client");
Console.WriteLine($"  Process ID: {Environment.ProcessId}");
Console.WriteLine();

using var client = new System.IO.Pipes.NamedPipeClientStream(
    serverName: ".",
    pipeName: PipeName,
    System.IO.Pipes.PipeDirection.InOut,
    System.IO.Pipes.PipeOptions.Asynchronous);

Console.WriteLine("Connecting...");
await client.ConnectAsync(timeout: 5000);
client.ReadMode = System.IO.Pipes.PipeTransmissionMode.Message;
Console.WriteLine("Connected! Type messages (or QUIT to exit):");

byte[] buffer = new byte[4096];

while (true)
{
    Console.Write("> ");
    string? input = Console.ReadLine();
    if (string.IsNullOrEmpty(input)) continue;

    await client.WriteAsync(Encoding.UTF8.GetBytes(input));
    await client.FlushAsync();

    if (input.Equals("QUIT", StringComparison.OrdinalIgnoreCase))
        break;

    int bytesRead = await client.ReadAsync(buffer);
    string response = Encoding.UTF8.GetString(buffer, 0, bytesRead);
    Console.WriteLine($"  <- {response}");
}

Console.WriteLine("Done.");

두 애플리케이션을 모두 실행하면 클라이언트가 메시지를 보내고 서버가 이를 그대로 되돌려 보내므로, 특별한 구성 없이도 완전 신뢰 수준의 두 데스크톱 프로세스 간 통신이 이루어짐을 확인할 수 있습니다.

Registry

IPC에 대한 레지스트리 사용은 일반적으로 권장되지 않지만 기존 코드에서는 지원됩니다. 패키지된 애플리케이션은 액세스 권한이 있는 레지스트리 키에만 액세스할 수 있습니다.

패키지된 데스크톱 앱( 코드에서 MSIX 패키지 빌드 참조)은 전역 레지스트리 쓰기가 MSIX 패키지 내의 프라이빗 하이브에 포함되도록 레지스트리 가상화를 활용합니다. 이렇게 하면 전역 레지스트리 영향을 최소화하면서 소스 코드 호환성을 사용할 수 있으며 동일한 패키지의 프로세스 간에 IPC에 사용할 수 있습니다. 레지스트리를 사용해야 하는 경우 이 모델은 전역 레지스트리 조작에 비해 선호됩니다.

원격 프로시저 호출 (RPC)

패키지된 애플리케이션에 RPC 엔드포인트의 ACL과 일치하는 올바른 기능이 있는 경우 RPC를 사용하여 패키지된 애플리케이션을 Win32 RPC 엔드포인트에 연결할 수 있습니다.

사용자 지정 기능을 사용하면 OEM 및 IHV가 임의 기능을 정의하고 RPC 엔드포인트를 ACL로 정의한 다음 권한 있는 클라이언트 애플리케이션에 해당 기능을 부여할 수 있습니다. 전체 샘플 애플리케이션은 CustomCapability 샘플을 참조하세요.

RPC 엔드포인트는 사용자 지정 기능의 관리 오버헤드 없이 엔드포인트에 대한 액세스를 해당 애플리케이션으로만 제한하기 위해 특정 패키지된 애플리케이션에 ACLed가 될 수도 있습니다. DeriveAppContainerSidFromAppContainerName API를 사용하여 패키지 패밀리 이름에서 SID를 파생한 다음 CustomCapability 샘플에 표시된 대로 SID를 사용하여 RPC 엔드포인트를 ACL할 수 있습니다.

공유 메모리

파일 매핑을 사용하여 다음 제약 조건을 사용하여 둘 이상의 프로세스 간에 파일 또는 메모리를 공유할 수 있습니다.

  • 기본적으로 패키지된 애플리케이션의 파일 매핑은 프로세스가 완전 신뢰가 아닌 한 동일한 패키지 내의 프로세스 간에만 지원됩니다.
  • 명명된 개체를 공유하기 위한 지침에 따라 패키지 간에 파일 매핑을 공유할 수 있습니다.

Windows 앱 SDK 데스크톱 앱은 완전 신뢰 프로세스로 실행되므로 제한 없이 공유 메모리 파일 매핑을 만들고 사용할 수 있습니다. 완전 신뢰가 없는 다른 패키지된 앱과 통신하는 경우 명명된 개체 공유에 설명된 ACL 접근 방식을 사용합니다.

공유 메모리는 대량의 데이터를 효율적으로 공유하고 조작하는 데 권장됩니다.

Loopback

루프백은 localhost(루프백 주소)에서 수신 대기하는 네트워크 서버와 통신하는 프로세스입니다.

보안 및 네트워크 격리를 유지하기 위해 IPC에 대한 루프백 연결은 기본적으로 패키지된 애플리케이션에 대해 차단됩니다. 기능 및 매니페스트 속성을 사용하여 신뢰할 수 있는 패키지된 애플리케이션 간에 루프백 연결을 사용하도록 설정할 수 있습니다.

  • 루프백 연결에 참여하는 모든 패키지된 애플리케이션은 privateNetworkClientServer에서 기능을 선언 해야 합니다.
  • 패키지된 두 애플리케이션은 패키지 매니페스트 내에서 LoopbackAccessRules 를 선언하여 루프백을 통해 통신할 수 있습니다.
    • 각 애플리케이션은 LoopbackAccessRules에 다른 애플리케이션을 나열해야 합니다. 클라이언트는 서버에 대한 "out" 규칙을 선언하고 서버는 지원되는 클라이언트에 대해 "in" 규칙을 선언합니다.

메모

이러한 규칙에서 애플리케이션을 식별하는 데 필요한 패키지 패밀리 이름은 개발 시간 동안 Visual Studio 패키지 매니페스트 편집기, Microsoft Store 통해 게시된 애플리케이션에 대한 파트너 센터 또는 이미 설치된 애플리케이션에 대한 Get-AppxPackage PowerShell 명령을 통해 찾을 수 있습니다.

패키지되지 않은 애플리케이션 및 서비스에는 패키지 ID가 없으므로 LoopbackAccessRules에서 선언할 수 없습니다. 패키지된 애플리케이션을 CheckNetIsolation.exe통해 패키지되지 않은 애플리케이션 및 서비스와 루프백을 통해 연결하도록 구성할 수 있지만, 이는 컴퓨터에 로컬 액세스 권한이 있고 관리자 권한이 있는 테스트용 로드 또는 디버깅 시나리오에만 가능합니다.

  • 패키지된 애플리케이션이 패키지되지 않은 애플리케이션 또는 서비스에 연결하는 경우 실행 CheckNetIsolation.exe LoopbackExempt -a -n=<PACKAGEFAMILYNAME> 하여 패키지된 애플리케이션에 대한 루프백 예외를 추가합니다.
  • 패키지되지 않은 애플리케이션 또는 서비스가 패키지된 애플리케이션에 연결하는 경우 패키지된 애플리케이션이 인바운드 루프백 연결을 수신할 수 있도록 실행 CheckNetIsolation.exe LoopbackExempt -is -n=<PACKAGEFAMILYNAME> 합니다.
    • 패키지 된 애플리케이션이 연결을 수신 대기하는 동안CheckNetIsolation.exe지속적으로 실행되어야 합니다.

메모

CheckNetIsolation.exe플래그에 -n 필요한 패키지 패밀리 이름은 개발 시간 동안 Visual Studio 패키지 매니페스트 편집기, Microsoft Store 통해 게시된 애플리케이션에 대한 파트너 센터 또는 이미 설치된 애플리케이션에 대한 Get-AppxPackage PowerShell 명령을 통해 찾을 수 있습니다.

IPC 메커니즘 선택

다음 표에는 IPC 메커니즘 및 최상의 사용 사례가 요약되어 있습니다.

메커니즘 적합한 대상 Requirements
앱 서비스 속성 백을 사용한 소규모 데이터 교환 패키지 ID를 사용하여 패키지된 앱
COM 재사용 가능한 구성 요소, 자동화 계층 없음 (Win32) 또는 패키지 매니페스트 (패키지된 COM)
명명된 파이프 스트림 기반 양방향 통신 완전 신뢰 앱의 경우 없음
공유 메모리 대용량 데이터, 고성능 완전 신뢰 앱의 경우 없음
원격 프로시저 호출 (RPC) 분산 클라이언트/서버 프로그램 ACL은 액세스를 허용해야 합니다.
Registry 레거시 코드 호환성 새 코드에 권장되지 않음
Loopback 네트워크 기반 프로토콜(TCP/UDP) privateNetworkClientServer 패키지된 앱에 대한 기능