네트워크 드라이브와 UNC 경로의 함정 ── 업무 앱에서 파일 서버(공유 폴더)를 다루는 실무
· 업데이트: · Go Komura · 네트워크 드라이브, UNC 경로, SMB, 파일 공유, Windows 서비스, 파일 서버, C#, .NET, 네트워크, 장애 조사, Windows 개발, 기술 상담
수정 이력(4건, 최종 수정 2026년 09월 03일)
이 글에 적용한 변경 사항의 기록입니다. 보관해 둔 수정 전 버전은 DOI가 부여된 고정 URL에서 읽을 수 있습니다.
- permalink·저자 표기·지식 맵 래퍼·깨진 내부 링크 등 CI가 지적한 표시용 수정을 반영했습니다. 본문의 기술적인 주장은 바꾸지 않았습니다.
- 글 서두에 「이 글의 지식 맵」 절을 추가했습니다. 본문에서 다루는 개념과 그 관계를 요약·그림·상세 페이지 링크로 정리한 것입니다. 본문의 주장은 바꾸지 않았습니다.
- 외부 리뷰(1283건) 대응으로 본문을 갱신했습니다. 개별 변경 내용은 아래 이력을 참조하세요.
- 가정하는 환경(OS, 공유 프로토콜, 인증 기반, 앱 실행 형태, 코드 예의 전제)을 서두의 표로 명시했습니다.
- 최초 공개
이 글을 인용하기(DOI(등록된 아카이브): 10.5281/zenodo.22174205)
아래 DOI는 이전에 등록된 아카이브를 가리키며 현재 본문과 다를 수 있습니다. 현재 본문을 참조할 때는 이 페이지의 URL을 사용하세요.
Go Komura (2026). 「네트워크 드라이브와 UNC 경로의 함정 ── 업무 앱에서 파일 서버(공유 폴더)를 다루는 실무」. 합동회사 코무라소프트. https://comcomponent.com/ko/blog/network-share-unc-path-pitfalls/
- DOI(등록된 아카이브)
- 10.5281/zenodo.22174205
- DOI(마지막 등록 버전)
- 10.5281/zenodo.22174206
「개발 머신에서는 됐는데, 고객 환경에서 『Z:\ 를 찾을 수 없습니다』라는 말을 듣는다」「작업 스케줄러에 올리자마자 공유 폴더 출력이 실패하기 시작했다」「Windows 서비스로 만들었더니 파일 서버가 보이지 않게 됐다」── 업무 앱 상담에서 파일 서버(공유 폴더) 문제는 가장 자주 나오는 유형입니다. 수주 데이터 수신, 장표나 CSV 출력, 장비가 내놓는 파일 감시. 온프레미스 업무 시스템에서 공유 폴더는 지금도 현역 연동 기반이기 때문입니다.
까다로운 점은 이런 문제의 상당수가 「코드 버그」가 아니라, 드라이브 문자와 로그온 세션의 관계, 서비스 실행 계정과 인증, SMB 연결 관리 같은 Windows 쪽 구조에 뿌리를 둔다는 것입니다. 디버거로 쫓아도 원인에 닿지 못하고, 「내 PC에서는 재현되지 않는다」인 채로 시간만 갑니다.
이 글은 공유 폴더로 파일을 출력·수신·감시하는 업무 앱 개발자(WinForms/WPF/Windows 서비스)를 대상으로, 네트워크 드라이브와 UNC 경로의 함정을 구조부터 정리하고 실무 정석을 판단표로 정리합니다.
가정하는 환경
인증 이야기는 전제가 바뀌면 답도 바뀌므로, 먼저 가정하는 환경을 밝혀 둡니다.
| 항목 | 가정 |
|---|---|
| OS | Windows 10 / 11, Windows Server(현재 지원 대상 버전) |
| 공유 프로토콜 | SMB(Windows의 일반적인 파일 공유) |
| 인증 기반 | Active Directory 도메인 환경을 주로 가정합니다. 도메인이 없는 워크그룹이나 NAS 고유 계정을 쓰는 경우에는 그때마다 「워크그룹에서는」이라고 구분해 말합니다 |
| 앱 실행 형태 | 데스크톱 앱(WinForms / WPF), Windows 서비스, 작업 스케줄러에서 시작하는 콘솔 앱 |
| 코드 예 | C# / .NET 6 이후(File.WriteAllBytesAsync와 is ... or ... 패턴 매칭을 사용합니다) |
도메인인지 워크그룹인지는 이 글에서 가장 크게 갈리는 분기입니다. 3장의 실행 계정 선택지(컴퓨터 계정이나 gMSA)는 도메인이 있어야 성립하고, 도메인이 없는 환경에서는 4장의 「자격 증명을 명시적으로 넘긴다」 쪽으로 기울게 됩니다. 자사가 어느 쪽인지 먼저 확인한 뒤 읽어 주십시오.
이 글에서 쓰는 약어
| 약어 | 읽기·정식 명칭 | 한 줄로 |
|---|---|---|
| UNC 경로 | Universal Naming Convention(유니버설 명명 규칙) | \\서버명\공유명\... 형식. 공유 폴더의 본래 주소 |
| SMB | Server Message Block | Windows 파일 공유에 쓰는 통신 프로토콜 |
| 로그온 세션 | ─ | 사용자가 로그온하거나 서비스가 시작될 때 OS가 만드는 「실행 맥락」. 드라이브 문자는 이 단위로 관리됩니다(2장) |
| Kerberos | ─ | Active Directory 도메인의 표준 인증 프로토콜. 티켓을 주고받아 본인 확인을 합니다 |
| SPN | Service Principal Name(서비스 주체 이름) | Kerberos에서 접속 대상 서비스를 가리키는 이름. 클라이언트는 접속 대상 호스트명으로 SPN을 만들어 티켓을 요청합니다(4장) |
| gMSA | group Managed Service Account(그룹 관리 서비스 계정) | 비밀번호를 OS가 자동 생성·자동 갱신하는 도메인 서비스 계정(3장)1 |
1. 먼저 결론
- 드라이브 문자(Z: 등)는 시스템 전역이 아니라 로그온 세션 단위입니다. 로그온 세션마다 A부터 Z까지 드라이브 문자 한 세트가 할당되므로, 다른 사용자의 프로세스나 다른 로그온 세션에서 동작하는 서비스에서는 사용자가 매핑한 드라이브가 보이지 않습니다.2
- UAC가 켜진 관리자 계정에서는 일반 권한용과 상승용, 두 개의 로그온 세션이 만들어지고, 드라이브 매핑(DosDevices 심볼릭 링크)은 세션마다 독립입니다. 그래서 「상승된 앱에서만 Z:가 보이지 않는다」가 일어납니다.
EnableLinkedConnections레지스트리로 두 세션에 공유시키는 우회책은 있지만, Microsoft가 「시스템을 덜 안전하게 만들 수 있으며 지원하지 않는다」고 명시한 비지원 설정입니다.34 - 서비스(나 다른 보안 컨텍스트의 프로세스)에서 원격 리소스에 접근할 때는 UNC 경로(
\\server\share\...)를 쓰는 것이 공식 지침입니다. 서비스 안에서net use나 WNet 계열 API로 드라이브 문자를 매핑하는 구현은 자격 증명 유출이나 서비스 간 간섭 때문에 권장되지 않습니다.2 - 공유 쪽에 권한을 줄 대상은 서비스 실행 계정으로 정해집니다. LocalSystem과 NetworkService는 네트워크에서 「컴퓨터 자격 증명」으로 인증되고, LocalService는 익명 자격 증명이 되므로 공유 접근에는 맞지 않습니다. 로컬 사용자 계정으로 도는 서비스는 네트워크 리소스에 접근할 수 없습니다. 실무에서 가장 유력한 선택은 도메인 계정이거나, 비밀번호 관리를 OS에 맡길 수 있는 gMSA(group Managed Service Account, 그룹 관리 서비스 계정)입니다. 다만 gMSA는 도메인 환경과 KDS 루트 키 준비가 전제입니다(3장).567819
- 같은 서버에 여러 자격 증명으로 동시에 연결할 수는 없습니다. 두 번째 연결은 오류 1219(
ERROR_SESSION_CREDENTIAL_CONFLICT)로 실패하며, 이는 사양(by design)입니다.1011 - 공유 폴더는 「느리고, 끊기고, 상대가 없을 수 있다」가 정상입니다. 유휴 연결은 기본값으로 15분 뒤 서버 쪽에서 끊깁니다(다음 접근에서 다시 연결).
File.Exists는 권한 부족이나 오류 때에도 예외 없이false를 반환하므로, 「파일이 없다」와 「서버에 닿지 않는다」를 구분하지 못합니다.1213 - FileSystemWatcher는 네트워크 드라이브와 원격 컴퓨터 감시를 지원하지만, 놓치는 경우를 전제로 설계합니다. 버퍼가 넘치면 이벤트를 잃을 수 있고, 네트워크 너머 감시에서는 내부 버퍼 상한이 64KB로 제한됩니다. 폴링(전체 스캔)을 함께 쓰는 것이 정석입니다.14
그림의 실선은 항상 성립하는 관계, 점선은 조건이 붙는 관계입니다(성립 조건은 상세 페이지의 관계별 설명에 적혀 있습니다). 관계 전체 목록(총 31건, 근거와 확신도 포함)과 주요 개념의 정의는 지식 맵 상세 페이지에 정리되어 있습니다(일본어). 데이터: JSON-LD / Turtle
2. 드라이브 문자와 UNC 경로의 관계 ── Z:는 「당신의 로그온 세션」의 것
탐색기에서 \\fileserver\share를 Z:에 할당하면, 마치 머신 전체에 「Z: 드라이브」가 생긴 것처럼 보입니다. 이것이 첫 오해입니다.
공식 문서의 설명은 분명합니다. 드라이브 문자는 시스템 전역이 아니라, 로그온 세션마다 A부터 Z까지 한 세트가 할당됩니다. 리디렉션된 드라이브(네트워크 드라이브)는 서로 다른 사용자 계정으로 도는 프로세스 사이에서 공유되지 않고, 다른 로그온 세션에서 도는 서비스는 다른 세션에서 잡은 드라이브 문자에 접근할 수 없습니다.2 Windows는 드라이브 매핑을, 로그온 세션을 고유하게 식별하는 로그온 SID를 기준으로 관리합니다.2
즉 Z:는 「경로 축약 기호가 로그온 세션마다 한 세트씩 있다」일 뿐이고, 실체는 언제나 UNC 경로입니다. 그림으로 그리면 다음과 같습니다.
flowchart TB
subgraph SA["로그온 세션 A ── 대화형으로 로그온한 사용자"]
EXP["탐색기<br/>데스크톱에서 시작한 앱"]
ZA["이 세션의 드라이브 문자 한 세트<br/>Z: 는 공유에 매핑됨"]
EXP --- ZA
end
subgraph SB["로그온 세션 B ── 서비스 / 작업 스케줄러"]
SVC["Windows 서비스<br/>예약된 배치"]
ZB["이 세션의 드라이브 문자 한 세트<br/>Z: 는 미할당"]
SVC --- ZB
end
UNC["공유 폴더의 실체<br/>UNC 경로 ── fileserver01 의 share"]
ZA -->|"Z: 로 도달할 수 있음"| UNC
ZB -.->|"Z: 는 없음. UNC 경로라면 도달할 수 있음"| UNC
그림 1: 드라이브 문자는 로그온 세션마다 한 세트이고, 실체인 UNC 경로는 하나뿐입니다
주의할 점은, 이 분리가 「사용자가 달라서」가 아니라는 것입니다. 서비스를 세션 A와 같은 사용자 계정으로 실행하도록 구성해도, Windows는 서비스용으로 새 로그온 세션을 만들기 때문에 세션 A에서 잡은 매핑은 이어지지 않습니다.2 「서비스 실행 사용자를 나와 같게 했는데도 아직 Z:를 찾을 수 없다」는 상담은, 여기를 착각한 경우가 원인입니다.
여기서부터 현장에서 자주 보는 증상을 이어서 설명할 수 있습니다.
| 증상 | 구조상의 이유 |
|---|---|
| 다른 사용자로 실행하니 Z:가 없다 | 드라이브 문자는 로그온 세션 단위. 다른 사람의 매핑은 보이지 않습니다2 |
| 「관리자 권한으로 실행」하면 Z:가 없다 | UAC로 일반용과 상승용 두 로그온 세션이 만들어지고, 매핑은 공유되지 않습니다3 |
| 작업 스케줄러/서비스에 올리니 Z:가 없다 | 다른 로그온 세션에서 실행되기 때문입니다. 서비스를 사용자 계정으로 구성해도 Windows는 서비스용으로 새 로그온 세션을 만듭니다2 |
UAC 건은 조금 더 짚어 둘 가치가 있습니다. 관리자 그룹 사용자가 로그온하면, Windows는 권한을 줄인 토큰과 완전한 관리자 토큰, 서로 연결된 두 로그온 세션을 만듭니다. 드라이브 매핑의 실체는 드라이브 문자와 UNC 경로를 잇는 심볼릭 링크 객체(DosDevices)이고, 이는 로그온 세션 고유라 세션 사이에 공유되지 않습니다.3 로그온 스크립트는 일반 권한 쪽에서 돌아가므로, 상승된 프로세스에서는 그 매핑이 보이지 않는다는 이야기입니다.
EnableLinkedConnections(HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System의 DWORD 값)를 1로 두면, 연결된 두 세션 모두에 심볼릭 링크가 쓰여 이 증상은 사라집니다. 다만 공식 문서에는 「이 우회책은 시스템을 덜 안전하게 만들 수 있다. Microsoft는 이 우회책을 지원하지 않는다. 자기 책임으로 사용할 것」이라고 명시되어 있습니다.4 고객 환경 레지스트리에 비지원 설정을 넣는 제안은, 업무 앱 해결책으로는 방향이 틀렸습니다. 앱 쪽을 UNC 경로로 쓰는 것이 정석입니다. 폴더 리디렉션 공식 문제 해결 문서에도 「드라이브 문자가 아니라 항상 UNC 경로 사용을 권장한다」고 되어 있습니다.4
구현은 단순합니다. 설정 파일에 저장하는 경로를 UNC로 두면 됩니다.
// appsettings.json ── 드라이브 문자가 아니라 UNC로 보관
{
"FileTransfer": {
"IncomingDir": "\\\\fileserver01\\edi\\incoming",
"ProcessedDir": "\\\\fileserver01\\edi\\processed"
}
}
사용자가 폴더 선택 대화상자에서 Z: 아래를 고를 수 있는 앱이라면, 저장할 때 UNC로 정규화해 두면 나중에 실행 컨텍스트가 바뀌어도 깨지지 않습니다. 드라이브 문자에서 UNC로 바꾸는 API로 WNetGetUniversalName이 준비되어 있습니다.15
3. Windows 서비스에서 공유 폴더에 접근하기 ── UNC 필수, 그리고 「누구로서」 접근하는가
앞 장에서 본 대로, 서비스에서는 매핑된 드라이브를 쓸 수 없습니다. 공식 문서는 서비스(및 다른 보안 컨텍스트에서 도는 프로세스)는 UNC 이름으로 원격 리소스에 접근해야 한다고 한 뒤, 서비스 안에서 net use나 WNet 계열 API로 실행 중에 드라이브 문자를 매핑하는 구현을 분명히 비권장합니다. 같은 컨텍스트에서 도는 다른 서비스에 매핑이 보인다, net use에 넘긴 자격 증명이 서비스 경계 밖으로 샐 수 있다, 여러 서비스가 같은 매핑을 잡으려다 「이미 연결됨」 오류로 서로 간섭한다, 가 이유로 나와 있습니다.2
UNC 경로로 바꿨다면 다음 문제는 인증입니다. 서비스는 「누구로서」 파일 서버에 접근하는가. 이는 실행 계정으로 정해지고, 공유 쪽에 권한을 줘야 할 대상도 이로 정해집니다.
| 실행 계정 | 네트워크상의 신원 | 공유 쪽 권한 부여 | 판단 |
|---|---|---|---|
| LocalSystem | 컴퓨터 자격 증명5 | 도메인 환경이라면 컴퓨터 계정(DOMAIN\MACHINE$)에 공유·NTFS 권한 | 동작은 하지만 권한이 과합니다. 머신 교체 시 권한 설정을 다시 해야 합니다 |
| NetworkService | 컴퓨터 자격 증명6 | 위와 같음 | 로컬 권한은 최소이고, 네트워크에서는 LocalSystem과 같은 신원입니다 |
| LocalService | 익명 자격 증명7 | 줄 방법이 없음 | 공유 접근에는 맞지 않음 |
| 로컬 사용자 | ─ | ─ | 네트워크 리소스에 접근 불가8 |
| 도메인 사용자 | 해당 계정 | 해당 계정에 부여 | 실무 표준. 비밀번호 변경 운영이 과제입니다 |
| gMSA | 해당 계정 | 해당 계정에 부여 | 비밀번호는 OS가 자동 관리(30일마다 자동 변경). 되는 환경이라면 가장 유력한 선택입니다116 |
LocalSystem과 NetworkService가 「컴퓨터로서」 네트워크로 나가는 것은 공식으로 명시된 사양입니다.56 BITS 문서에는 그 결과로 「원본 파일 ACL이 사용자 계정으로 접근을 제한하면, (컴퓨터 자격 증명으로 인증되는) 서비스는 접근 거부가 된다」, 「시스템 계정은 매핑된 드라이브를 쓰면 안 된다」는 실무 주의가 그대로 적혀 있습니다.17
여기서 나오는 실무 지침은 다음 세 가지입니다.
- 「서비스로 만들었더니 접근 거부」의 1차 원인 분리는 실행 계정 확인입니다. 데스크톱에서 돌 때는 「당신」의 권한이고, 서비스에서는 위 표의 신원으로 접근 검사가 이뤄집니다. 공유 사용 권한과 NTFS ACL 모두를 그 신원에 대해 확인합니다.
- 도메인 환경에서 오래 운영한다면 실행 계정은 도메인 계정 또는 gMSA로 둡니다. gMSA는 240바이트 난수 비밀번호를 30일마다 OS가 자동 갱신하므로, 「서비스 계정 비밀번호 만료로 월요일 아침에 전부 멈췄다」 같은 사고를 구조적으로 없앨 수 있습니다.16
- 워크그룹 환경(도메인 없음)에서는 컴퓨터 자격 증명 인증이 성립하지 않으므로, 다음 장의 명시적 자격 증명이 등장합니다.
그 gMSA에는 전제가 있습니다. 「가장 유력한 선택」이라고 썼지만, 마음먹은 날 바로 쓰는 물건이 아닙니다. gMSA는 원래 단일 서버용 sMSA(standalone Managed Service Account) 기능을 여러 서버에 걸쳐 쓰도록 확장한 것이고, 자동 비밀번호 관리와 SPN 관리 단순화를 제공하는 도메인 계정입니다.1 도입 전에 다음을 확인하십시오.
| 전제 | 내용 |
|---|---|
| Active Directory 도메인 | gMSA는 도메인 계정입니다. 워크그룹 환경에서는 선택지가 되지 않습니다. 또한 Windows Server 2012보다 앞선 Windows에는 적용되지 않습니다1 |
| KDS 루트 키 | 도메인 컨트롤러는 gMSA 비밀번호를 만들려면 Key Distribution Service(KDS) 루트 키가 필요합니다. 포리스트에 한 번만 Add-KdsRootKey -EffectiveImmediately를 실행해 만듭니다9 |
| 만든 뒤 대기 시간 | 루트 키 생성 후 최대 10시간, 모든 도메인 컨트롤러의 AD 복제가 수렴할 때까지 gMSA를 만들 수 없습니다. 모든 DC가 gMSA 요청에 응할 수 있게 되기 전에 비밀번호가 만들어지지 않게 하려는 안전장치라, 「만들자마자 못 쓴다」는 사양입니다9 |
| 관리 단말 | gMSA를 관리하는 Windows PowerShell 명령을 실행하려면 64비트 아키텍처가 필요합니다19 |
| 암호화 유형 | gMSA는 Kerberos가 지원하는 암호화 유형에 의존합니다. 호스트에서 RC4를 끄고 msDS-SupportedEncryptionTypes 속성이 없으면 인증이 반드시 실패하므로, MSA에는 항상 AES를 구성해야 한다고 되어 있습니다1 |
도메인 관리자와 맞춰야 하는 항목이 이어지므로, gMSA를 전제로 한 설계를 제안한다면 위 다섯 가지를 인프라 담당자에게 먼저 확인하는 것이 순서입니다. 확인이 안 되거나 10시간 대기가 일정에 들어가지 않으면, 우선 일반 도메인 계정으로 짜 두고 gMSA 전환은 실행 계정 변경만으로 끝나게 해 두는 편이 현실적입니다.
서비스 자체 만드는 법(실행 계정 설정, 복구 옵션, 안전한 중지)은 「Windows 서비스 만드는 법과 운영」에서, 세션과 로그온 구조는 「Windows 세션 분리를 어떻게 이해할 것인가」에서 정리했습니다.
4. 자격 증명 다루기 ── net use·자격 증명 관리자·오류 1219
실행 계정 자체에 공유 쪽 권한을 줄 수 없는 경우(워크그룹, NAS가 자체 계정제인 경우 등)에는 자격 증명을 명시적으로 넘겨 연결하게 됩니다. 수단은 주로 세 가지입니다.
net use \\server\share /user:...── 그 로그온 세션에 연결을 잡습니다. 대화형 확인에는 편하지만, 앞 장에서 본 대로 서비스 안에서의 실행은 비권장입니다.2- 자격 증명 관리자(
cmdkey) ──cmdkey /add:server /user:svc-file /pass:...로 저장해 두면, 이후 그 서버 인증 때 저장된 자격 증명이 자동으로 쓰입니다.1819 저장은 사용자 프로필 단위이므로, 서비스에서 쓰려면 「서비스 실행 계정 컨텍스트에서」 등록해야 한다는 점이 함정입니다. - 프로그램에서 연결(
WNetAddConnection2) ── 클라이언트 자격 증명을 지정해 네트워크 리소스 연결을 잡을 수 있습니다. 공식 문서도 서버 프로세스가 네트워크 리소스에 접근하는 전략 중 하나로 들고 있습니다.20 드라이브 문자를 할당하지 않는 「deviceless 연결」로 두면 UNC 경로 그대로 접근할 수 있습니다.
그리고 이 영역에서 가장 유명한 함정이 오류 1219입니다.
Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. (ERROR_SESSION_CREDENTIAL_CONFLICT, 1219)11
같은 서버에 대해, 같은 로그온 세션에서 서로 다른 사용자 이름으로 여러 연결을 잡을 수는 없습니다. 「영업 공유는 내 계정, 시스템 연동용 공유는 전용 계정」처럼 같은 파일 서버에 두 종류의 자격 증명으로 붙으려 하면, 두 번째가 1219로 실패합니다. 공식 문서는 이를 「by design(사양)」이라고 분명히 하고, 우회책으로 드는 것은 「IP 주소로 연결한다」「다른 DNS 별칭을 만들어 연결한다」── 즉 다른 서버처럼 보이게 하는 방법입니다.10
실무에서는 애초에 한 서버에 여러 자격 증명을 나눠 쓰는 구성을 피하는 것이 첫 선택입니다. 연동용 계정을 하나로 모으고, 필요한 공유 모두에 그 계정 권한을 붙입니다. 그게 안 되는 사정이 있을 때만, 별칭(alias)으로 경로를 나눕니다.
다만 별칭은 「DNS에 CNAME 한 줄이면 끝」이 아닙니다. Kerberos 인증 환경에서는 SMB 클라이언트가 접속 대상 이름에 해당하는 SPN(서비스 주체 이름)으로 인증하려 하므로, 별칭에 대한 SPN이 등록되어 있지 않으면 CNAME을 통한 접근 자체가 실패할 수 있습니다. 공식 문제 해결 문서도 이 SPN 누락을 원인 중 하나로 들고, DNS CNAME이 아니라 netdom computername <서버명> /add:<별칭>으로 컴퓨터 이름 별칭으로 구성하는 방법을 안내합니다.21 별칭을 통한 연결은 1219 대책으로 설계에 넣기 전에 반드시 대상 환경에서 동작을 검증하십시오.
참고로 「서비스가, 접속해 온 클라이언트 사용자의 권한으로 파일 서버에 접근하고 싶다」는 고급 요건은 자격 증명 재사용이 아니라 가장(impersonation)의 영역입니다. 공식 문서도 서비스가 자격 증명을 끌어안기보다 가장을 권장합니다.2 가장의 올바른 작성법과, 원격 리소스에서 추가로 고려해야 할 점은 「Windows 가장 토큰을 올바르게 다루기」를 보십시오.
자기 환경을 진단하기 ── 먼저 실행할 명령
여기까지의 이야기는, 증상이 나는 환경에서 상태를 확인할 수 있어야 비로소 실무가 됩니다. 원인 분리의 출발점은 그 프로세스가 누구로서 돌고 있고, 어떤 연결을 가지고 있는가입니다. 다음 세 가지를, 증상이 나는 것과 같은 실행 컨텍스트에서 실행하십시오.
| 명령 | 알 수 있는 것 | 볼 포인트 |
|---|---|---|
whoami |
지금 자신이 누구로서 도는지(도메인명\사용자명 형식으로 표시됩니다) |
가정한 실행 계정과 맞는지. 서비스라면 3장 표의 어느 행인지 |
net use(인수 없음) |
그 로그온 세션이 가진 네트워크 연결 목록22 | 없어야 할 Z:가 목록에 있는지. 없으면 「그 세션에는 없다」가 확정됩니다 |
net use \\fileserver01\share |
지정한 연결의 상태22 | 연결 자체가 안 잡힌 것인지, 잡은 뒤 권한에서 막힌 것인지 |
핵심은 같은 컨텍스트에서 실행하는 것입니다. 자기 데스크톱에서 net use를 쳐도, 서비스가 가진 연결 이야기가 되지 않습니다. 서비스 실행 계정으로 확인하고 싶을 때는, 작업 스케줄러에 같은 계정·같은 권한 설정으로 cmd /c "whoami > C:\temp\who.txt & net use >> C:\temp\who.txt" 같은 작업을 잠시 등록하고, 그 출력 파일을 보는 것이 확실합니다.
오류 1219를 직접 재현하기
1219는 설명을 읽는 것보다 한 번 직접 내 보는 편이 빨리 와닿습니다. 도메인에 가입한 단말에서, 같은 파일 서버의 두 공유에 서로 다른 자격 증명으로 연결해 보십시오.
:: 1) 자기 계정으로 첫 번째 공유에 연결한다(비밀번호는 * 로 프롬프트 입력)
net use \\fileserver01\share1 * /user:CONTOSO\tanaka
:: 2) 같은 서버의 다른 공유에, 다른 계정으로 연결하려고 한다
net use \\fileserver01\share2 * /user:CONTOSO\svc-file
:: → 여기서 위에 인용한 오류 1219가 반환되어 연결할 수 없다
:: 뒷정리: 이 세션의 네트워크 연결을 모두 끊는다
net use * /delete
포인트는 공유가 달라도 서버가 같으면 충돌한다는 것입니다. 첫 번째가 share1, 두 번째가 share2여도 상관없습니다. 제약은 서버 단위이기 때문입니다. 반대로 첫 번째 연결을 net use \\fileserver01\share1 /delete로 끊은 뒤 두 번째를 잡으면 성공합니다 ── 즉 순서에 따라서는 통과해 버리기 때문에, 개발 중에는 재현되지 않다가 운영에서 처음 나오는 불쾌한 형태를 띱니다. 우회책으로 IP 주소나 별칭을 쓸 때는, 바로 앞에서 말한 SPN 전제를 잊지 마십시오.1021
5. 「느리고, 끊기고, 상대가 없을 수 있다」를 전제로 설계하기
로컬 디스크와 같은 감각으로 쓴 코드는, 공유 폴더를 상대로는 반드시 어딘가에서 사고가 납니다. 전제로 삼을 현실은 세 가지입니다.
첫째, 연결이 끊기는 것이 정상입니다. 유휴 연결은 서버 자원 낭비를 막기 위해 기본값으로 15분 타임아웃 뒤에 끊깁니다. 탐색기 네트워크 드라이브에 빨간 ×가 붙는 익숙한 현상이 이것이고, 다음에 접근하면 곧바로 다시 연결됩니다.12 즉 「가끔만 접근하는 업무 앱이 접근할 때마다 잠깐 기다린다」「감시 도구가 『끊겼다!』고 떠들지만 실제 피해는 없다」 둘 다 사양대로의 동작입니다. 연결의 존재를 감시하는 것이 아니라, 실제 I/O가 성공하는가로 판단합니다.
이 타임아웃은 바꿀 수 있습니다. 다만 서버 쪽과 클라이언트 쪽 두 곳에 타이머가 있고, 짧은 쪽이 이긴다는 점에 주의하십시오.12
| 어디 | 설정 | 내용 |
|---|---|---|
| 서버 쪽(명령) | net config server /autodisconnect:<분> |
유휴 끊김까지의 분수. 최댓값은 65,535. 0을 지정해도 무효화가 되지 않고, 몇 초 유휴면 끊기게 되는 점이 함정입니다 |
| 서버 쪽(명령) | net config server /autodisconnect:-1 |
autodisconnect 기능 자체를 끕니다 |
| 서버 쪽(레지스트리) | HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanserver\parameters의 autodisconnect(REG_DWORD) |
타임아웃 변경만. 이 방법으로는 기능을 끌 수 없습니다 |
| 클라이언트 쪽(레지스트리) | HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanworkstation\parameters의 KeepConn(REG_DWORD, 1〜65535초) |
클라이언트 쪽 유휴 유지 시간. 기본값은 600초(10분) |
놓치기 쉬운 것은 마지막 행입니다. 클라이언트 쪽 기본값은 10분이고, 서버 쪽 기본 15분보다 짧기 때문에, 서버 쪽만 늘려도 끊김 동작은 바뀌지 않습니다. 세션은 autodisconnect와 KeepConn의 짧은 쪽 값으로 끊기기 때문입니다.12
그렇다고 해도 이 값들을 바꾸는 것은 첫 선택이 아닙니다. 끊김은 사양대로의 동작이고, 다음 접근에서 다시 연결되므로 실제 피해가 없는 것이 보통입니다. 값을 만지는 것은, 끊길 때마다 죽는 오래된 앱을 안고 있어 손을 못 대는 식의 사정이 있을 때로 한정하고, 다른 시스템에도 영향을 주는 설정임을 감안해 서버 관리자와 합의한 뒤에 하십시오. 앱 쪽은 「끊기는 전제로 재시도한다」로 모으는 것이 본줄기입니다.
둘째, 오류가 나오는 방식이 불친절합니다. File.Exists는 경로가 잘못돼도, 권한이 모자라도, 디스크 장애여도, 예외 없이 false를 반환합니다.13 로컬에서는 「false면 없다」로 거의 곤란하지 않지만, 공유를 상대로는 「파일이 없다」와 「서버에 닿지 않는다/권한이 없다」가 모두 false로 뭉개지므로, Exists로 분기해 업무 판단을 하는 코드는 네트워크 장애 때 『대상 없음』으로 정상 종료한다는 불쾌한 깨짐을 보입니다. 존재 확인을 끼우지 않고 열어 가서 예외로 구분하는 편이, 공유를 상대로는 진단하기 쉬운 설계입니다.
셋째, 상대가 아직 없을 수 있습니다. 머신 기동 직후에는 네트워크 준비보다 서비스 시작이 앞서는 경우가 있고, 파일 서버 쪽이 재시작 중일 수도 있습니다. 지속 연결(persistent connection)은 사용자 로그온 때 복원되는 구조이므로23, 로그온을 거치지 않는 서비스 세계에서는 「시작하면 공유가 보인다」는 보장이 없습니다. 시작 때 한 번만 통신을 확인하고 실패하면 종료하는 것이 아니라, 재시도하면서 기다리는 것이 올바른 동작입니다.
이 셋을 넣으면, 쓰기 쪽 골격은 이렇게 됩니다.
// 일시적인 네트워크 오류는 재시도, 업무 오류는 즉시 실패시킨다
private static async Task WriteToShareAsync(string finalPath, byte[] content, CancellationToken ct)
{
var dir = Path.GetDirectoryName(finalPath)!;
var tempPath = Path.Combine(dir, $"~{Guid.NewGuid():N}.tmp");
try
{
for (var attempt = 1; ; attempt++)
{
try
{
await File.WriteAllBytesAsync(tempPath, content, ct);
File.Move(tempPath, finalPath); // 같은 디렉터리 안의 rename으로 「완성」을 공개
return;
}
catch (IOException ex) when (attempt < 5 && IsRetryable(ex))
{
// 일시적인 네트워크 장애만 지수 백오프로 재시도(상한 있음)
_logger.LogWarning(ex, "공유로의 쓰기 실패({Attempt}회째). 재시도합니다", attempt);
await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempt)), ct);
}
}
}
catch
{
// 포기하고 예외를 전파할 때는, 임시 파일을 최선을 다해 치운다
try { File.Delete(tempPath); } catch { /* 치우기 실패는 무시한다 */ }
throw;
}
}
// IOException은 「네트워크 끊김」도 「이동 대상에 같은 이름 파일」도 「디스크 가득」도 같은 형으로 온다.
// HResult의 하위 16bit(Win32 오류 코드)로, 재시도할 의미가 있는 일시 장애만 고른다
private static bool IsRetryable(IOException ex)
{
var win32 = ex.HResult & 0xFFFF;
return win32 is 53 // ERROR_BAD_NETPATH: 네트워크 경로를 찾을 수 없음
or 59 // ERROR_UNEXP_NET_ERR: 예기치 않은 네트워크 오류
or 64 // ERROR_NETNAME_DELETED: 네트워크 이름을 더 이상 사용할 수 없음
or 121; // ERROR_SEM_TIMEOUT: 타임아웃(이른바 세마포어 타임아웃)
}
「IOException이면 재시도」라고 대충 쓰지 않는 것도 중요합니다. 이동 대상에 같은 이름 파일이 있다, 경로가 너무 길다, 디스크가 가득하다는 몇 번을 해도 결과가 바뀌지 않는 실패도 같은 IOException으로 오기 때문에, 예외 형만으로 판정하면 영구 오류를 5번 재시도하며 쓸데없이 백오프로 기다리게 됩니다. 위 예처럼 Win32 오류 코드(53/59/64/121 등, 공유 접근의 끊김·타임아웃 계열24)로 「재시도할 의미가 있는 실패」만 고르십시오. 실제 환경 로그에서 관측한 코드를 더해 가는 운영이 현실적입니다.
포인트는 재시도를 붙이는 것 자체보다, 재시도해도 안전한 전달 프로토콜(temp -> rename, idempotency)과 세트로 넣는 것입니다. 쓰기 도중 끊기면 어중간한 파일이 남습니다. final 이름은 「닫은 뒤의 rename」으로만 나타난다는 약속으로 두면, 수신 쪽이 설익은 파일을 읽는 사고를 막을 수 있습니다. 참고로 프로세스 크래시나 전원 차단에서는 코드 안 치우기 자체가 돌지 않으므로, 전달 폴더에는 「~*.tmp 가운데 일정 시간 갱신이 없는 것을 삭제한다」는 정기 청소도 함께 마련해 두면 쓰레기 축적으로 막히지 않습니다. 이 전달 설계의 전체 그림은 「파일 연동의 배타 제어 기초 지식」에 정리했습니다.
하나 더, 네트워크 상대 특유의 주의가 있습니다. 「실패했다」는 결과는 정말로 실패했음을 보장하지 않습니다. 서버 쪽에서 rename이 끝난 직후 연결이 끊기면, 클라이언트에는 예외가 돌아오는데 final 이름 파일은 이미 공개된 상태가 일어날 수 있습니다. 이 채로 아무 생각 없이 재시도하면, 「이동 대상에 이미 같은 이름 파일이 있다」 오류로 막히거나, 수신 쪽이 이미 첫 번째를 가져간 경우에는 같은 데이터를 이중으로 공개하게 됩니다. 대책은 rename 단계 실패를 재시도하기 전에 이동 대상 상태를 확인해 맞춰 보는 것입니다. final 이름에 처리 ID(전표 번호나 실행 GUID)를 넣어 두면, 「같은 ID의 final 파일이 이미 있다 = 이전 rename은 사실 성공이었다」고 판정해 성공으로 빠져나갈 수 있고, 수신 쪽도 ID 중복으로 이중 수신을 걸러낼 수 있습니다.
6. SMB 너머의 배타 제어와 FileSystemWatcher의 신뢰성
6.1. 잠금에 대한 과신은 금물
공유 폴더는 여러 클라이언트가 동시에 만집니다. FileShare.None으로 열면 열려 있는 동안의 배타는 SMB 너머에서도 동작하지만, 「잠금을 잡으면 안전하다」에 기댄 설계는, 끊김으로 핸들을 잃었을 때, 잠금을 잡지 않는 상대(손으로 복사, 다른 시스템)가 섞였을 때 무너집니다. 배타의 본체는 OS의 잠금이 아니라, temp -> rename·원자적 claim(incoming에서 processing으로의 rename 승자만 처리한다)·idempotency라는 전달 프로토콜 쪽에 두어야 합니다. 생각의 자세한 내용은 위의 배타 제어 글로 넘깁니다.
6.2. FileSystemWatcher를 원격 공유에서 쓸 때의 현실
FileSystemWatcher는 로컬뿐 아니라 네트워크 드라이브와 원격 컴퓨터의 파일 감시를 지원한다고 공식으로 명시되어 있습니다.14 쓰는 것 자체는 정당합니다. 다만 신뢰성의 전제가 두 가지 있습니다.
- 알림은 버퍼를 거치며, 넘치면 놓칩니다. 변경이 짧은 시간에 몰리면 버퍼 크기를 넘긴 만큼의 이벤트는 사라집니다.14
- 네트워크 너머 감시에서는
InternalBufferSize상한이 64KB로 제한됩니다. 로컬보다 「키울 수 없는」 제약이 명문화되어 있습니다.14
게다가 공유 저편에서 서버 재시작이나 끊김이 일어났을 때, 감시만 조용히 죽어 있고 알림이 오지 않는다는 증상은 장애 조사 현장에서 반복해서 봐 왔습니다. 원격 공유의 FileSystemWatcher는 「빨리 알아채기 위한 힌트」로 보고, 시작 시·오류 시·주기적 전체 스캔(폴링)을 진실의 원천으로 삼는 것이 실무의 결론입니다. 이벤트 중복·순서 붕괴에 대한 대응까지 포함한 설계 패턴은 「FileSystemWatcher 실무 가이드」에서 자세히 다룹니다.
7. 실무 정석(판단표)
여기까지의 내용을, 설계 때 헷갈리는 논점별 판단표로 정리합니다.
| 논점 | 선택지 | 판단의 가늠 |
|---|---|---|
| 경로를 보관하는 방식 | 드라이브 문자 / UNC 경로 | 앱이 다루는 경로는 항상 UNC. 드라이브 문자는 사용자 화면상의 편의로 봅니다2 |
| 공유로의 쓰기 | 직접 쓰기 / temp -> rename | 직접 쓰기는 「도중 파일을 읽히지 않는다」는 보장이 없습니다. final 이름=완성이라는 약속이 기본입니다 |
| 새 파일 감지 | FileSystemWatcher 단독 / 폴링 / 함께 사용 | 원격 공유에서는 놓침을 전제로 합니다. 몇 분 간격이 허용되면 폴링만 쓰는 편이 단순하고 단단합니다. 즉시성이 필요하면 함께 사용합니다14 |
| 서비스 실행 계정 | LocalSystem / 도메인 계정 / gMSA | 공유 접근이 있으면 도메인 계정 또는 gMSA. gMSA가 되는 환경이라면 비밀번호 운영까지 없앨 수 있습니다1 |
| 자격 증명이 따로 필요할 때 | 코드에서 net use를 실행 / WNetAddConnection2 / cmdkey 사전 등록 | 서비스 안의 net use는 비권장. 같은 서버에 여러 자격 증명은 1219로 막히므로, 계정 통합 또는 DNS 별칭으로 설계 단계부터 피합니다210 |
| 클라이언트 다수가 직접 접근 | 각 단말이 UNC 직접 / 중간 서비스(API) 경유 | 단말 수×자격 증명×동시 접근을 관리할 수 없게 되면, 공유를 만지는 것은 서비스 하나로 모으고 클라이언트는 API로 말하게 구성을 옮깁니다 |
마지막 행은 보태 둡니다. 공유 폴더 연동은 손쉽지만, 접근하는 쪽이 늘수록 「누가 어떤 권한으로」「누구와 누가 경쟁하는가」 관리가 지수적으로 어려워집니다. 어느 규모를 넘으면 파일 서버를 만지는 프로세스를 Windows 서비스 하나로 모으고, 각 클라이언트와는 HTTP나 gRPC로 대화합니다. 공유 폴더를 「시스템 간 인터페이스」에서 「그 서비스의 내부 구현」으로 격하하는 것이, 장기적으로 가장 유지하기 쉬운 형태입니다.
8. 정리
- 드라이브 문자는 로그온 세션 단위의 기호일 뿐입니다. 다른 사용자·상승 프로세스·서비스에서 보이지 않는 것은 사양이고, 앱은 UNC 경로로 쓰는 것이 정석입니다.
EnableLinkedConnections는 비지원 우회책입니다. - 서비스에서의 공유 접근은 UNC 필수입니다. 누구로서 인증되는지는 실행 계정으로 정해지고, LocalSystem/NetworkService는 컴퓨터 자격 증명, LocalService는 익명입니다. 실무는 도메인 계정 또는 gMSA에 공유 쪽 권한을 줍니다.
- 같은 서버에 여러 자격 증명을 동시에 연결하면 오류 1219로 실패합니다(사양). 계정 통합 또는 DNS 별칭으로 설계 단계부터 피합니다.
- 공유는 「느리고, 끊기고, 상대가 없을 수 있다」가 정상입니다. 유휴 끊김(기본 15분)은 이상이 아니고,
File.Exists의 false는 네트워크 장애와 구분되지 않습니다. 재시도와 temp -> rename, idempotency를 세트로 넣습니다. - FileSystemWatcher는 원격 감시를 지원하지만, 버퍼 넘침으로 인한 놓침과 64KB 상한이 있으므로 전체 스캔을 함께 쓰는 것이 정석입니다.
- 헷갈리면 7장 판단표로 가십시오. 규모가 커지면 공유를 만지는 프로세스를 중간 서비스로 모으는 구성도 검토해 주십시오.
관련 글
- 파일 연동의 배타 제어 기초 지식 - 파일 잠금과 원자적 claim의 베스트 프랙티스
- FileSystemWatcher 실무 가이드 - 놓침과 중복 대책
- Windows 서비스 만드는 법과 운영 ── 작업 스케줄러와의 역할 분담부터 BackgroundService의 서비스화까지
- Windows 세션 분리를 어떻게 이해할 것인가 ── Session 0·RDP·여러 사용자 동시 실행
- Windows 가장 토큰을 올바르게 다루기 ── 스레드 단위 권한 차용과 안전한 되돌림
관련 상담 영역
합동회사 코무라소프트에서는 공유 폴더를 통한 파일 연동 시스템의 설계·구현, Windows 서비스화에 따른 접근 권한·인증 구성 검토, 「서비스로 만들었더니 공유가 보이지 않는다」「특정 환경에서만 실패한다」 같은 장애 조사를 다룹니다.
참고 링크
-
Microsoft Learn, Group Managed Service Accounts overview. gMSA가 자동 비밀번호 관리와 SPN 관리 단순화를 제공하는 도메인 계정이며, 비밀번호 관리를 Windows OS에 맡길 수 있다는 점에 대해. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8
-
Microsoft Learn, Services and Redirected Drives. 드라이브 문자가 시스템 전역이 아니라 로그온 세션마다 할당된다는 점, 서비스는 다른 세션의 드라이브 문자에 접근할 수 없어 UNC 이름을 써야 한다는 점, 서비스 안에서 net use·WNet 함수로 드라이브 매핑하는 것이 비권장인 이유(자격 증명 유출, 서비스 간 간섭 등), 사용자 계정으로 구성한 서비스에도 새 로그온 세션이 만들어진다는 점, 자격 증명을 끌어안기보다 클라이언트 가장이 권장된다는 점에 대해. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12
-
Microsoft Learn, Mapped drives are not available from an elevated prompt when UAC is configured to Prompt for credentials. UAC가 켜져 있을 때 연결된 두 로그온 세션이 만들어진다는 점, 드라이브 매핑의 실체가 로그온 세션 고유의 심볼릭 링크 객체(DosDevices)라 세션 사이에 공유되지 않는다는 점, EnableLinkedConnections가 두 세션에 심볼릭 링크 쓰기를 강제한다는 점에 대해. ↩ ↩2 ↩3
-
Microsoft Learn, Folder Redirection fails to apply when redirected to mapped drive letter, instead of UNC path. 관리자 로그온 때 LSA가 두 액세스 토큰을 만들고 표준 토큰으로 드라이브가 매핑된다는 점, EnableLinkedConnections 레지스트리 값 설정 절차와 「시스템을 덜 안전하게 만들 수 있으며 Microsoft는 지원하지 않는다」는 경고, 드라이브 문자가 아니라 UNC 경로 사용이 항상 권장된다는 점에 대해. ↩ ↩2 ↩3
-
Microsoft Learn, LocalSystem Account. LocalSystem이 로컬에서 폭넓은 권한을 가지며, 네트워크에서는 컴퓨터 자격 증명을 원격 서버에 제시한다는 점에 대해. ↩ ↩2 ↩3
-
Microsoft Learn, NetworkService Account. NetworkService가 로컬에서는 최소 권한이고, 네트워크에서는 컴퓨터 자격 증명을 원격 서버에 제시한다는 점에 대해. ↩ ↩2 ↩3
-
Microsoft Learn, LocalService Account. LocalService가 네트워크에서 익명 자격 증명을 제시한다는 점에 대해. ↩ ↩2
-
Microsoft Learn, About Service Logon Accounts. 서비스 로그온 계정이 실행 시 보안 컨텍스트를 정한다는 점, 로컬 사용자 계정 보안 컨텍스트로 도는 서비스는 네트워크 리소스에 접근할 수 없다는 점에 대해. ↩ ↩2
-
Microsoft Learn, Create a Key Distribution Service (KDS) Root Key. 도메인 컨트롤러가 gMSA 비밀번호 생성에 KDS 루트 키가 필요하다는 점,
Add-KdsRootKey -EffectiveImmediately로 만든다는 점, 생성 후 최대 10시간은 모든 도메인 컨트롤러의 AD 복제가 수렴할 때까지 gMSA를 만들 수 없다는 점(모든 DC가 gMSA 요청에 응할 수 있게 되기 전의 비밀번호 생성을 막는 안전장치), gMSA 관리 명령 실행에 64비트 아키텍처가 필요하다는 점에 대해. ↩ ↩2 ↩3 ↩4 -
Microsoft Learn, The network folder specified is currently mapped using a different user name and password error. 같은 서버에 서로 다른 자격 증명으로 여러 연결을 하려 할 때의 오류가 by design(사양)이라는 점, 우회책이 IP 주소 연결 또는 다른 DNS 별칭 생성이라는 점에 대해. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, System Error Codes (1000-1299). 오류 1219(ERROR_SESSION_CREDENTIAL_CONFLICT)의 정의와 메시지에 대해. ↩ ↩2
-
Microsoft Learn, Mapped drive connection to network share may be lost. 유휴 연결이 기본값으로 15분 타임아웃 뒤 끊긴다는 점(autodisconnect), 탐색기 드라이브 아이콘에 빨간 ×가 표시되지만 접근하면 곧바로 다시 연결된다는 점,
net config server /autodisconnect:<분>으로 타임아웃을 바꿀 수 있고 최댓값이 65,535라는 점,0을 지정해도 기능은 꺼지지 않고 몇 초 유휴면 끊기게 된다는 점,-1로 기능을 끌 수 있다는 점, 서버 쪽 레지스트리HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanserver\parameters의autodisconnect로는 타임아웃 변경만 가능하고 무효화는 안 된다는 점, 클라이언트 쪽 레지스트리HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanworkstation\parameters의KeepConn(REG_DWORD, 1〜65535초, 기본 600초)이 있으며 세션은 autodisconnect와 KeepConn의 짧은 쪽 값으로 끊긴다는 점에 대해. ↩ ↩2 ↩3 ↩4 -
Microsoft Learn, File.Exists(String) Method. 읽기 권한이 없으면 예외 없이 false를 반환한다는 점, 존재 판정 중 어떤 오류가 발생한 경우(잘못된 경로, 디스크 장애, 권한 부족 등)에도 false를 반환한다는 점에 대해. ↩ ↩2
-
Microsoft Learn, FileSystemWatcher Class. 로컬 컴퓨터·네트워크 드라이브·원격 컴퓨터의 파일 감시를 지원한다는 점, 버퍼 크기 초과 시 이벤트를 놓칠 수 있다는 점, 네트워크 너머 감시에서는 InternalBufferSize 최댓값이 64KB라는 점에 대해. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, WNet Functions. WNetGetUniversalName이 드라이브 기반 경로에서 유니버설(UNC) 형식 이름을 가져오는 함수라는 점에 대해. ↩
-
Microsoft Learn, Secure group managed service accounts. gMSA 비밀번호가 240바이트 난수 생성이고, OS가 30일마다 자동 변경하므로 관리자의 비밀번호 변경 계획이나 서비스 중지가 필요 없어진다는 점에 대해. ↩ ↩2
-
Microsoft Learn, Service Accounts and BITS. LocalSystem/NetworkService의 네트워크 인증이 컴퓨터 자격 증명, LocalService가 익명 자격 증명으로 이뤄진다는 점, ACL이 사용자 계정으로 한정되어 있으면 접근 거부가 된다는 점, 시스템 계정이 매핑된 드라이브를 쓰면 안 된다는 점에 대해. ↩
-
Microsoft Learn, cmdkey. cmdkey 명령으로 저장된 사용자 이름과 비밀번호(자격 증명)를 만들고 목록을 보고 삭제할 수 있다는 점에 대해. ↩
-
Microsoft Learn, Credentials processes in Windows authentication. 자격 증명 관리자가 자격 증명을 Windows 자격 증명 컨테이너에 저장하고, 이후 인증 때 자동으로 제시한다는 점에 대해. ↩
-
Microsoft Learn, Client Access to Network Resources. 서버 프로세스가 네트워크 리소스에 접근하는 전략으로, 클라이언트 자격 증명을 지정한 WNetAddConnection2로 연결을 잡는 방법이 제시된다는 점에 대해. ↩
-
Microsoft Learn, SMB file server share access is unsuccessful through DNS CNAME alias. CNAME을 통한 SMB 접근이 실패하는 원인 중 하나가 별칭에 대한 SPN 미등록이라는 점, DNS CNAME이 아니라 netdom computername 명령으로 별칭을 정의하는 방법이 안내된다는 점에 대해. ↩ ↩2
-
Microsoft Learn, Net use. 매개변수 없이 실행하면 네트워크 연결 목록을 가져온다는 점,
net use <장치명>으로 특정 연결 정보를 표시할 수 있다는 점, 비밀번호에*를 지정하면 프롬프트로 입력할 수 있다는 점,/user로 다른 사용자 이름을 지정할 수 있다는 점,/delete에*를 지정하면 모든 네트워크 연결이 해제된다는 점에 대해. ↩ ↩2 -
Microsoft Learn, Windows Networking Operations. 지속 연결(persistent connection)이 사용자 로그온 때 시스템이 자동 복원하는 네트워크 연결이라는 점에 대해. ↩
-
Microsoft Learn, System Error Codes (0-499). ERROR_BAD_NETPATH(53), ERROR_UNEXP_NET_ERR(59), ERROR_NETNAME_DELETED(64), ERROR_SEM_TIMEOUT(121) 각 정의에 대해. ↩
관련 기사
같은 태그를 공유하는 최신 기사입니다. 더 가까운 주제로 지식을 넓힐 수 있습니다.
슬립・최대 절전 모드・Modern Standby와 장시간 가동 앱 ── '한밤중에 멈춰 있었다'를 설계로 막는다
장시간 동작하는 Windows 앱이 '아침에 보니 멈춰 있었다'가 되는 원인을 S3 슬립/최대 절전 모드/Modern Standby의 차이에서 정리합니다. 슬립 중 타이머와 TCP 연결의 동작, SetThreadExecutionState로 억제하...
MAX_PATH와 Windows 경로·파일 이름의 함정 ── 260자 제한, 예약 이름, 끝의 점, 대소문자
「파일을 찾을 수 없습니다」의 단골 원인인 경로·파일 이름 제한을 정리합니다. MAX_PATH=260자의 구성, LongPathsEnabled로 긴 경로를 켜는 방법, CON 등의 예약 이름, 끝 점의 정규화, Path.Combine의 함정까지 ...
자사 개발 Windows 앱이 바이러스로 오인되면 ── Microsoft Defender 오탐 대응과 성능 영향에 대처하는 법
자사 개발 Windows 앱이 Microsoft Defender에 오탐되었을 때의 정규 대응을 정리합니다. 현대 바이러스 백신의 동작 방식, Microsoft에 오탐을 신고하는 방법, 격리에서 복원하기, 제외 설정을 올바르게 넣는 방법과 그 위험...
Windows on Arm에서 업무 앱은 동작하는가 ── x64 에뮬레이션(Prism)과 네이티브 DLL·COM의 현실
「Windows on Arm에서 업무 앱은 동작하는가」에 개발자와 사내 IT를 위해 답합니다. x64 에뮬레이션(Prism)의 구조, 드라이버처럼 동작하지 않는 계층, .NET의 AnyCPU와 P/Invoke 문제, Arm 대응 체크리스트까지 정...
Windows 앱의 작업 트레이 상주와 토스트 알림 ── NotifyIcon의 함정과 AppNotification 고르는 법
업무용 Windows 앱의 작업 트레이 상주와 토스트 알림 구현을 정리합니다. NotifyIcon의 올바른 사용법, Explorer 재시작 시 재등록, 토스트 API 3종의 선정 판단표, 알림이 도착하지 않는 경우까지 설명합니다.
관련 토픽
이 기사와 가까운 토픽 페이지입니다. 기사를 출발점 삼아 관련 서비스와 다른 기사로 이어집니다.
Windows 기술 토픽
Windows 개발, 장애 조사, 기존 자산 활용에 관한 KomuraSoft LLC 기사를 모은 토픽 허브입니다.
장애 조사 & 장기 가동 장애
간헐적 장애, 통신 진단, 장기 가동 크래시, 실패 경로 테스트 기반을 정리한 토픽 페이지입니다.
이 주제와 연결되는 서비스
이 기사는 다음 서비스 페이지로 이어집니다. 가까운 입구부터 확인해 주세요.
Windows 앱 개발
상주 처리, 장비 연동, 운영 로그, 유지 보수 가능한 구조가 필요한 Windows 데스크톱 애플리케이션을 지원합니다.
장애 조사 & 원인 분석
간헐적 장애, 장기 가동 중 크래시, 누수, 통신 중단 등 까다로운 프로덕션 이슈를 조사합니다.
자주 묻는 질문
이 기사 주제에 대해 상담 시 자주 나오는 질문을 모았습니다.
- Windows 서비스에서 네트워크 드라이브(Z:)에 접근할 수 없는 이유는 무엇인가요?
- 드라이브 문자가 시스템 전역이 아니라 로그온 세션 단위이기 때문입니다. 사용자가 탐색기에서 매핑한 Z:는 그 사용자 로그온 세션에 속한 기호일 뿐이라, 다른 로그온 세션에서 동작하는 서비스에서는 보이지 않습니다. 서비스를 사용자 계정으로 실행하더라도 Windows는 서비스용으로 새 로그온 세션을 만들기 때문에, 같은 계정이라도 데스크톱에서 매핑한 드라이브는 이어지지 않습니다. 서비스에서는 \\server\share 형식의 UNC 경로로 접근하는 것이 맞습니다.
- LocalSystem으로 동작하는 서비스에서 공유 폴더에 접근하려면 어떻게 하나요?
- LocalSystem은 네트워크에서 컴퓨터 자격 증명으로 인증됩니다. 도메인 환경이라면 공유 쪽(공유 사용 권한과 NTFS ACL)에 해당 머신의 컴퓨터 계정(DOMAIN\MACHINE$) 권한을 부여하면 접근할 수 있습니다. 다만 머신을 교체하면 권한 설정을 다시 해야 하는 등 운영이 번거로우므로, 실무에서는 서비스 실행 계정을 도메인 계정 또는 gMSA(그룹 관리 서비스 계정)로 두고, 그 계정에 공유 쪽 권한을 주는 구성을 권장합니다.
- 공유 폴더의 파일을 FileSystemWatcher로 감시해도 되나요?
- 사용할 수는 있지만, 그것만 단독으로 믿어서는 안 됩니다. FileSystemWatcher는 네트워크 드라이브와 원격 컴퓨터 감시를 지원하지만, 변경 알림은 버퍼를 거쳐 전달되므로 알림이 몰리면 버퍼가 넘쳐 이벤트를 놓칩니다. 게다가 네트워크 너머 감시에서는 버퍼 상한이 64KB로 제한됩니다. 알림은 '다시 스캔할 계기'로만 보고, 시작 시·오류 시·주기적 전체 스캔(폴링)을 반드시 함께 쓰는 것이 정석입니다.
- 네트워크 끊김에 강한 파일 연동을 만들려면 어떻게 하나요?
- '공유는 느리고, 끊기고, 상대가 없을 수 있다'를 정상 상태로 두고 설계합니다. 구체적으로는 쓰기를 임시 파일명으로 한 뒤 close 후에 rename으로 공개하고(temp -> rename), 읽기·쓰기를 재시도로 감싸며, 일시적인 네트워크 오류와 업무 오류를 구분합니다. File.Exists는 접근할 수 없을 때도 false를 반환하므로 '파일이 없다'와 '서버에 닿지 않는다'를 구분하지 못합니다. 다시 처리해도 깨지지 않는 idempotency(멱등성)를 마지막 방어선으로 두는 것이 중요합니다.