← 기술 백서 목록으로 돌아가기

[제100편 기념] 웹 브라우저의 샌드박스를 넘어 물리 하드웨어를 제어하다: ZeliDesk WebBridge의 RS232 시리얼 통신 특허 아키텍처 및 ConcurrentDictionary 멀티 포트 오케스트레이션

"웹 기술(HTML5/JavaScript)이 데스크톱의 표준 프론트엔드로 진화했음에도 불구하고, W3C 웹 샌드박스의 철통같은 보안 장벽으로 인해 로컬 PC의 하드웨어(RS232 시리얼 포트, 산업용 계측기, 초·중·고 정보 교과용 아두이노 및 마이크로비트)를 직접 제어하는 것은 불가능에 가까웠습니다. ZeliDesk WebBridge는 웹페이지와 WinUI 3 네이티브 런타임 간의 양방향 비동기 통신을 규격화하여, 브라우저 JavaScript 코드 한 줄로 물리 시리얼 포트를 탐색·개방·스트리밍하는 독자 특허 아키텍처를 완성했습니다. ConcurrentDictionary 기반 스레드 안전 멀티포트 격리, 3초 타임아웃 예외 가드, 그리고 이벤트 기반 무지연 데이터 수신 파이프라인을 통해 웹 대시보드와 피지컬 컴퓨팅 하드웨어를 하나로 묶어낸 ZeliDesk 100번째 엔지니어링 백서를 공개합니다."

1. 웹 샌드박스의 오랜 장벽: 브라우저에서 물리 하드웨어를 직접 제어할 수 없는 이유

현대 소프트웨어 개발 생태계에서 웹 프론트엔드는 가장 미려한 반응형 차트, 풍부한 애니메이션, 그리고 실시간 대시보드를 제공합니다. 그러나 초·중·고 정보 교과의 피지컬 컴퓨팅 실습(센서 데이터 수집, 로봇 모터 제어)이나 군부대 상황실의 국방 통신 장비(GPS 수신기, 레이더 계측기, 시리얼 무전기)를 제어하려 할 때 웹은 커다란 벽에 부딪힙니다.

웹 브라우저는 보안상의 이유로 OS의 저수준 I/O(RS232, COM 포트, 물리 메모리)에 접근하지 못하도록 격리된 샌드박스 안에서만 동작하기 때문입니다:

  1. Web Serial API의 극심한 제약: 크롬 계열 일부 브라우저가 실험적으로 지원하는 Web Serial API는 사용자가 매번 번거로운 팝업을 승인해야 하며, 브라우저 탭을 닫으면 연결이 끊어지고 다중 포트 백그라운드 상주가 불가능합니다.
  2. 로컬 웹소켓/HTTP 데몬의 보안 취약점: 별도의 로컬 서버(localhost:8080 등)를 백그라운드로 띄워 통신하는 우회 방식은 포트 충돌, 방화벽 차단, 그리고 악성 웹사이트가 로컬 포트로 침투하는 CSRF/CORS 공격에 무방비로 노출됩니다.
  3. COM 포트 잠금(Port Locking)과 데드락: 시리얼 통신은 하나의 프로세스가 포트를 점유하면 다른 프로세스가 열지 못하는 배타적 자원입니다. 비정상 종료 시 포트가 잠겨 PC를 재부팅해야 하는 만성 결함이 발생합니다.

ZeliDesk는 이 난제를 돌파하기 위해 WebBridge RS232 특허 기술을 개발했습니다. 외부 포트 노출 없는 인프로세스(In-Process) WebView2 메시지 채널과 C# 네이티브 SerialPortManager를 유기적으로 결합하여, 완벽한 보안 격리와 0ms 하드웨어 제어 능력을 동시에 달성했습니다.

비교 항목 W3C Web Serial API 로컬 웹소켓/HTTP 데몬 방식 ZeliDesk WebBridge 특허 아키텍처
통신 채널 브라우저 실험적 구현 (불안정) 로컬 TCP 소켓 (방화벽/포트 충돌 위험) WebView2 IPC 네이티브 메시지 (외부 노출 0%)
포트 관리 단일 포트 위주, 권한 팝업 강제 다중 포트 시 스레드 충돌 빈발 ConcurrentDictionary 기반 완벽한 병렬 멀티포트
백그라운드 지속 탭 비활성화 시 연결 중단 위험 별도 데몬 프로세스 상주 필요 런처 코어 수명주기와 완전 일체화 (0ms 백그라운드)
보안성 제한적 샌드박스 CORS/CSRF 로컬 침해 공격에 취약 ZeliDesk 서명 검증 샌드박스 완전 격리
개발 생산성 복잡한 스트림 리더/라이터 구현 소켓 핸드셰이크 직접 구현 필요 ZeliBridge.openPort('COM3') 단 한 줄로 완료

2. 핵심 아키텍처 1: WebBridge RS232 특허 프로토콜 (`zelidesk-bridge.js`)

웹 프론트엔드 개발자는 복잡한 C++ Win32 API나 C# P/Invoke를 전혀 몰라도 됩니다. ZeliDesk가 제공하는 가벼운 자바스크립트 SDK인 zelidesk-bridge.js를 포함하는 것만으로, 전통적인 웹 이벤트 모델(on, emit)을 통해 시리얼 장비와 실시간 대화를 나눌 수 있습니다:

JavaScript (ZeliDesk WebBridge SDK v2.0 클라이언트 호출)
// 1. ZeliDesk 런처 환경 감지
if (ZeliBridge.isAvailable()) {
    // 2. 사용 가능한 COM 포트 목록 조회
    ZeliBridge.listPorts();

    // 3. C# 네이티브 이벤트 수신 등록
    ZeliBridge.on('serial_ports', (ports) => {
        console.log('연결된 하드웨어 포트 목록:', ports); // ["COM1", "COM3", "COM7"]
        // COM3 포트를 115200 보드레이트로 즉시 개방
        ZeliBridge.openPort('COM3', { baud: 115200, parity: 'None', dataBits: 8, stopBits: 'One' });
    });

    // 4. 센서 데이터 실시간 스트리밍 수신 (0ms 무지연)
    ZeliBridge.on('serial_data', (payload) => {
        // payload = { port: "COM3", data: "SENSOR:TEMP=24.5,HUMI=60\r\n" }
        updateSensorDashboard(payload.data);
    });

    // 5. 하드웨어로 제어 명령 송신
    function sendMotorCommand(speed) {
        ZeliBridge.writePort('COM3', `MOTOR:SET_SPEED=${speed}\n`);
    }
}

window.chrome.webview.postMessage를 통해 전송된 JSON 명령은 호스트 WinUI 3 런타임의 WebMessageReceived 이벤트 핸들러에서 가로채어져, 네이티브 SerialPortManager 인스턴스로 0초 만에 디스패치됩니다.

3. 핵심 아키텍처 2: ConcurrentDictionary 기반 스레드 안전 멀티포트 격리

실제 공교육 정보 실습실이나 군 전산실에서는 단 하나의 시리얼 장비만 연결되지 않습니다. 학생 한 명이 아두이노 보드(COM3)와 온습도 센서(COM4), 그리고 모터 드라이버(COM5)를 동시에 연결하여 복합 시스템을 제어합니다.

C#의 기본 Dictionary<TKey, TValue>는 다중 스레드 환경에서 데이터 경합(Race Condition) 시 프로세스 크래시를 유발합니다. SerialPortManager는 고성능 논블로킹 동시성 컬렉션인 ConcurrentDictionary<string, SerialPort>를 도입했습니다:

C# (ZeliDesk.Services.SerialPortManager 멀티포트 코어)
public class SerialPortManager : IDisposable
{
    // 열려 있는 포트들을 안전하게 관리 (포트 이름 → SerialPort 인스턴스)
    private readonly ConcurrentDictionary<string, SerialPort> _openPorts = new();

    public event Action<string, string> DataReceived;   // (portName, data)
    public event Action<string, string> ErrorOccurred;  // (portName, errorMessage)

    public bool Open(string portName, int baudRate = 9600, string parity = "None",
                     int dataBits = 8, string stopBits = "One")
    {
        try
        {
            if (_openPorts.ContainsKey(portName))
            {
                ErrorOccurred?.Invoke(portName, $"포트 '{portName}'가 이미 열려 있습니다.");
                return false;
            }

            var port = new SerialPort
            {
                PortName = portName,
                BaudRate = baudRate,
                Parity = ParseParity(parity),
                DataBits = dataBits,
                StopBits = ParseStopBits(stopBits),
                Encoding = Encoding.UTF8,
                ReadTimeout = 3000,
                WriteTimeout = 3000
            };
            // ... 이벤트 등록 및 포트 개방 ...
            port.Open();
            _openPorts[portName] = port;
            return true;
        }
        catch (Exception ex)
        {
            ErrorOccurred?.Invoke(portName, $"열기 실패: {ex.Message}");
            return false;
        }
    }
}

이로 인해 수십 개의 포트가 비동기로 동시에 열리고 닫히며 데이터를 쏟아내더라도 단 하나의 스레드 교착(Deadlock)이나 메모리 오염 없이 완벽하게 독립적으로 동작합니다.

4. 핵심 아키텍처 3: 0ms 인터럽트 비동기 스트리밍 (DataReceived)

시리얼 통신에서 CPU 사용량을 폭증시키는 최악의 안티패턴은 `while(true)` 루프로 버퍼를 계속 폴링(Polling)하는 것입니다. 수업용 저사양 컴퓨터실 PC에서 폴링 방식을 사용하면 CPU 사용률이 100%로 치솟아 화면이 버벅입니다.

ZeliDesk는 OS 커널 레벨의 하드웨어 인터럽트 이벤트인 port.DataReceived를 기반으로 수신 버퍼에 바이트가 도달하는 즉시 비동기로 콜백을 발생시킵니다:

C# (이벤트 기반 비동기 스트리밍 및 에러 격리)
port.DataReceived += (s, e) =>
{
    try
    {
        var sp = (SerialPort)s;
        string data = sp.ReadExisting();
        if (!string.IsNullOrEmpty(data))
        {
            // 수신 즉시 WebBridge를 거쳐 브라우저 자바스크립트로 0ms 전달!
            DataReceived?.Invoke(portName, data);
        }
    }
    catch (Exception ex)
    {
        ErrorOccurred?.Invoke(portName, $"읽기 오류: {ex.Message}");
    }
};

port.ErrorReceived += (s, e) =>
{
    ErrorOccurred?.Invoke(portName, $"하드웨어 포트 오류: {e.EventType}");
};

하드웨어로부터 데이터가 들어오지 않을 때는 CPU 점유율이 정확히 **0.0%**를 유지하며, 센서가 데이터를 밀어 넣는 순간에만 마이크로초 단위로 깨어나 UTF-8 디코딩 후 브라우저 웹소켓/IPC로 밀어 넣어 줍니다.

5. 핵심 아키텍처 4: 타임아웃 가드 및 포트 잠금 방지 IDisposable 수명주기

시리얼 장비는 물리적인 케이블 분리, 전원 차단, 또는 통신 노이즈로 인해 쓰기(Write)나 읽기(Read) 명령이 영원히 멈추는 블로킹(Blocking) 현상이 발생하기 쉽습니다.

SerialPortManager는 ReadTimeout = 3000, WriteTimeout = 3000의 3초 안전 임계값을 기본 설정하여 케이블이 갑자기 뽑히더라도 스레드가 무한 대기에 빠지지 않고 즉시 ErrorOccurred 이벤트를 발생시키며 안전하게 복구됩니다.

또한 창이 닫히거나 런처가 종료될 때 Dispose()를 통해 열려 있는 모든 COM 포트를 순회하며 안전하게 닫습니다:

C# (철저한 COM 포트 잠금 해제 IDisposable)
public void Dispose()
{
    foreach (var kvp in _openPorts)
    {
        try
        {
            if (kvp.Value.IsOpen) kvp.Value.Close();
            kvp.Value.Dispose(); // Windows 커널 포트 핸들 완전 반환
        }
        catch { }
    }
    _openPorts.Clear();
}

이로써 "장치가 사용 중이어서 포트를 열 수 없습니다"라는 Windows의 악명 높은 시리얼 포트 고착 문제를 원천 차단했습니다.

6. [제100편 기념 에필로그]: 100편의 엔지니어링 백서가 증명한 온디바이스 AI의 미래

ZeliDesk 엔지니어링 팀은 #999(ZeliGen 코어 엔진 v2)부터 이번 #900(WebBridge & SerialPortManager 특허 아키텍처)까지, 실제 제품에 구현된 방대한 솔루션 코드베이스를 한 줄 한 줄 검증하며 정확히 100편의 기술 백서를 연속 집필했습니다.

"서버가 꺼져도, 인터넷이 끊겨도, 학교 교실과 국방 작전망은 단 1초도 멈추지 않는다."
ZeliDesk 100편의 엔지니어링 백서는 단순한 기술 문서가 아니라, 대한민국 공교육의 교원 주권과 국가 안보를 수호하는 소프트웨어 독립 선언문입니다.

← 이전 기술 백서 #901 관리자 권한 없이 완성하는 40대 PC 원클릭 배포: ZeliDesk UpdateService의 .appinstaller 프로토콜 연동 및 패키지 무결성 버전 거버넌스 아키텍처 다음 기술 백서 → #899 초·중·고 교실과 교과서가 요구하는 4대 온디바이스 AI 패밀리: zLM·yLM·tLM·nLM의 에이전틱 사고력 확장 및 교원 통합 거버넌스 백서
🎉 ZeliDesk 100편 백서 달성 기념 — Suite 무료 체험하기

웹 브라우저와 물리 하드웨어를 잇는 RS232 WebBridge 특허 기술과 40여 종 온디바이스 AI 도구를 직접 경험하세요.

ZeliDesk Suite 무료 다운로드