네트워크 드라이브와 UNC 경로의 함정 ── 업무 앱에서 파일 서버(공유 폴더)를 다루는 실무

· · 네트워크 드라이브, UNC 경로, SMB, 파일 공유, Windows 서비스, 파일 서버, C#, .NET, 네트워크, 불량 조사, Windows 개발, 기술 상담

“개발 머신에서는 동작했는데 고객 환경에서는 ‘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.WriteAllBytesAsyncis ... 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

2. 드라이브 문자와 UNC 경로의 관계 ── Z:는 “당신의 로그온 세션”의 것

탐색기에서 \\fileserver\share를 Z:에 할당하면, 마치 머신 전체에 “Z: 드라이브”가 생긴 것처럼 보입니다. 이것이 첫 번째 오해입니다.

공식 문서의 설명은 명확합니다. 드라이브 문자는 시스템 전역이 아니라 로그온 세션마다 A부터 Z까지 한 세트가 할당됩니다. 리디렉션된 드라이브(네트워크 드라이브)는 서로 다른 사용자 계정으로 동작하는 프로세스 간에 공유할 수 없으며, 다른 로그온 세션에서 동작하는 서비스는 다른 세션에서 확립된 드라이브 문자에 접근할 수 없습니다.2 시스템은 드라이브 매핑을 로그온 세션을 고유하게 식별하는 로그온 SID를 기준으로 관리합니다.2

즉 Z:는 “경로의 축약 기호가 로그온 세션마다 한 세트씩 있다”는 것뿐이며, 실체는 항상 UNC 경로입니다. 그림으로 나타내면 다음과 같습니다.

로그온 세션 B ── 서비스 / 태스크 스케줄러로그온 세션 A ── 대화형으로 로그온한 사용자Z:로 도달 가능Z:는 존재하지 않음. UNC 경로라면 도달 가능Windows 서비스예약된 배치이 세션의 드라이브 문자 세트Z:는 미할당탐색기데스크톱에서 실행한 앱이 세션의 드라이브 문자 세트Z:는 공유에 매핑됨공유 폴더의 실체UNC 경로 ── fileserver01 의 share

그림 1: 드라이브 문자는 로그온 세션마다 한 세트씩 있으며, 실체인 UNC 경로는 하나뿐이다

주의할 점은 이 분리가 “사용자가 다르기 때문”이 아니라는 것입니다. 서비스를 세션 A와 같은 사용자 계정으로 실행하도록 구성해도, 시스템은 서비스용으로 새로운 로그온 세션을 만들기 때문에 세션 A에서 만든 매핑을 이어받지 못합니다.2 “서비스의 실행 사용자를 나와 같게 했는데도 여전히 Z:를 찾을 수 없다”는 상담은 이 부분을 착각한 것이 원인입니다.

여기서부터 현장에서 자주 발생하는 증상을 줄줄이 설명할 수 있습니다.

증상 구조상의 이유
다른 사용자로 실행하면 Z:가 없다 드라이브 문자는 로그온 세션 단위. 다른 사람의 매핑은 보이지 않는다2
“관리자 권한으로 실행”하면 Z:가 없다 UAC로 일반용과 상승용, 두 개의 로그온 세션이 만들어지며 매핑은 공유되지 않는다3
태스크 스케줄러/서비스에 올리면 Z:가 없다 다른 로그온 세션에서 실행되기 때문. 서비스를 사용자 계정으로 구성해도 시스템은 서비스용으로 새로운 로그온 세션을 만든다2

UAC 건은 조금 더 자세히 짚어 둘 가치가 있습니다. 관리자 그룹의 사용자가 로그온하면, 시스템은 권한을 제한한 토큰과 완전한 관리자 토큰이라는 연결된 두 개의 로그온 세션을 만듭니다. 드라이브 매핑의 실체는 드라이브 문자와 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로의 변환에는 WNetGetUniversalName이라는 API가 마련되어 있습니다.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를 전제로 한 설계를 제안한다면 위의 5가지 항목을 인프라 담당자에게 먼저 확인하는 것이 순서입니다. 확인을 받을 수 없거나 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\parametersautodisconnect(REG_DWORD) 타임아웃 변경만 가능. 이 방법으로는 기능을 비활성화할 수 없음
클라이언트 측(레지스트리) HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanworkstation\parametersKeepConn(REG_DWORD, 1~65535초) 클라이언트 측의 유휴 유지 시간. 기본값은 600초(10분)

놓치기 쉬운 것은 마지막 행입니다. 클라이언트 측의 기본값은 10분으로, 서버 측 기본값인 15분보다 짧기 때문에, 서버 측만 늘려도 끊기는 동작은 바뀌지 않습니다. 세션은 autodisconnectKeepConn더 짧은 쪽의 값으로 끊기기 때문입니다.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
    {
        // 포기하고 예외를 전파시킬 때는, 임시 파일을 최선을 다해(best-effort) 정리한다
        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장의 판단표를 참고하십시오. 규모가 커지면 공유를 다루는 프로세스를 중간 서비스로 집약하는 구성도 검토해 보십시오.

관련 글

관련 상담 영역

합동회사 코무라소프트에서는 공유 폴더를 통한 파일 연계 시스템의 설계・구현, Windows 서비스화에 따르는 접근 권한・인증 관련 구성 검토, “서비스로 만들었더니 공유가 보이지 않는다”, “특정 환경에서만 실패한다” 같은 불량 조사를 다루고 있습니다.

참고 링크

  1. Microsoft Learn, Group Managed Service Accounts overview. gMSA가 자동 비밀번호 관리와 SPN 관리 간소화를 제공하는 도메인 계정이며, 비밀번호 관리를 Windows OS에 맡길 수 있다는 점에 대해.  2 3 4 5 6 7 8

  2. Microsoft Learn, Services and Redirected Drives. 드라이브 문자가 시스템 전역이 아니라 로그온 세션마다 할당된다는 점, 서비스는 다른 세션의 드라이브 문자에 접근할 수 없어 UNC 이름을 사용해야 한다는 점, 서비스 내에서의 net use・WNet 함수에 의한 드라이브 매핑이 권장되지 않는 이유(자격 증명 유출, 서비스 간 간섭 등), 사용자 계정으로 구성한 서비스에도 새로운 로그온 세션이 만들어진다는 점, 자격 증명을 끌어안는 것보다 클라이언트 위장이 권장된다는 점에 대해.  2 3 4 5 6 7 8 9 10 11 12

  3. Microsoft Learn, Mapped drives are not available from an elevated prompt when UAC is configured to Prompt for credentials. UAC 활성화 시 연결된 두 개의 로그온 세션이 만들어진다는 점, 드라이브 매핑의 실체가 로그온 세션 고유의 심볼릭 링크 객체(DosDevices)이며 세션 간에 공유되지 않는다는 점, EnableLinkedConnections가 두 세션 모두에 심볼릭 링크 기록을 강제한다는 점에 대해.  2 3

  4. Microsoft Learn, Folder Redirection fails to apply when redirected to mapped drive letter, instead of UNC path. 관리자 로그온 시 LSA가 두 개의 액세스 토큰을 만들고 표준 토큰으로 드라이브가 매핑된다는 점, EnableLinkedConnections 레지스트리 값 설정 절차와 “시스템을 안전하지 않게 만들 수 있으며 Microsoft는 지원하지 않는다”는 경고, 드라이브 문자가 아니라 UNC 경로 사용이 항상 권장된다는 점에 대해.  2 3

  5. Microsoft Learn, LocalSystem Account. LocalSystem이 로컬에서 광범위한 특권을 가지며, 네트워크상에서는 컴퓨터 자격 증명을 원격 서버에 제시한다는 점에 대해.  2 3

  6. Microsoft Learn, NetworkService Account. NetworkService가 로컬에서는 최소한의 특권을 가지며, 네트워크상에서는 컴퓨터 자격 증명을 원격 서버에 제시한다는 점에 대해.  2 3

  7. Microsoft Learn, LocalService Account. LocalService가 네트워크상에서는 익명 자격 증명을 제시한다는 점에 대해.  2

  8. Microsoft Learn, About Service Logon Accounts. 서비스의 로그온 계정이 실행 시의 보안 컨텍스트를 결정한다는 점, 로컬 사용자 계정의 보안 컨텍스트로 동작하는 서비스가 네트워크 리소스에 접근할 수 없다는 점에 대해.  2

  9. 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

  10. Microsoft Learn, The network folder specified is currently mapped using a different user name and password error. 동일한 서버에 서로 다른 자격 증명으로 여러 개 연결하려 할 때의 에러가 by design(사양)이라는 점, 우회책이 IP 주소 접속 또는 별도의 DNS 별칭 생성이라는 점에 대해.  2 3 4

  11. Microsoft Learn, System Error Codes (1000-1299). 에러 1219(ERROR_SESSION_CREDENTIAL_CONFLICT)의 정의와 메시지에 대해.  2

  12. 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\parametersautodisconnect로는 타임아웃 변경만 가능하며 비활성화는 할 수 없다는 점, 클라이언트 측 레지스트리 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanworkstation\parametersKeepConn(REG_DWORD, 1~65535초, 기본 600초)이 있으며 세션은 autodisconnect와 KeepConn 중 더 짧은 쪽의 값으로 끊긴다는 점에 대해.  2 3 4

  13. Microsoft Learn, File.Exists(String) Method. 읽기 권한이 없는 경우 예외를 내지 않고 false를 반환한다는 점, 존재 판정 중 어떠한 오류가 발생한 경우(잘못된 경로, 디스크 장애, 권한 부족 등)에도 false를 반환한다는 점에 대해.  2

  14. Microsoft Learn, FileSystemWatcher Class. 로컬 컴퓨터・네트워크 드라이브・원격 컴퓨터의 파일 감시를 지원한다는 점, 버퍼 크기 초과 시 이벤트를 놓칠 수 있다는 점, 네트워크 너머의 감시에서는 InternalBufferSize의 최댓값이 64KB라는 점에 대해.  2 3 4 5

  15. Microsoft Learn, WNet Functions. WNetGetUniversalName이 드라이브 기반 경로로부터 유니버설(UNC) 형식의 이름을 가져오는 함수라는 점에 대해. 

  16. Microsoft Learn, Secure group managed service accounts. gMSA의 비밀번호가 240바이트의 무작위 생성이며, OS가 30일마다 자동으로 변경하기 때문에 관리자에 의한 비밀번호 변경 계획이나 서비스 중단이 불필요해진다는 점에 대해.  2

  17. Microsoft Learn, Service Accounts and BITS. LocalSystem/NetworkService의 네트워크 인증이 컴퓨터 자격 증명으로, LocalService가 익명 자격 증명으로 이루어진다는 점, ACL이 사용자 계정으로 한정되어 있는 경우 접근이 거부된다는 점, 시스템 계정이 매핑된 드라이브를 사용해서는 안 된다는 점에 대해. 

  18. Microsoft Learn, cmdkey. cmdkey 명령어로 저장된 사용자 이름과 비밀번호(자격 증명)를 생성・목록 표시・삭제할 수 있다는 점에 대해. 

  19. Microsoft Learn, Credentials processes in Windows authentication. 자격 증명 관리자가 자격 증명을 Windows 자격 증명 컨테이너에 저장하고, 다음 인증 시부터 자동으로 제시한다는 점에 대해. 

  20. Microsoft Learn, Client Access to Network Resources. 서버 프로세스가 네트워크 리소스에 접근하는 전략으로, 클라이언트의 자격 증명을 지정한 WNetAddConnection2에 의한 연결 확립이 제시되고 있다는 점에 대해. 

  21. Microsoft Learn, SMB file server share access is unsuccessful through DNS CNAME alias. CNAME을 경유한 SMB 접근이 실패하는 원인 중 하나가 별칭에 대한 SPN 미등록이라는 점, DNS의 CNAME이 아니라 netdom computername 명령어로 별칭을 정의하는 방법이 안내되고 있다는 점에 대해.  2

  22. Microsoft Learn, Net use. 매개변수 없이 실행하면 네트워크 연결 목록을 가져온다는 점, net use <장치명>으로 특정 연결의 정보를 표시할 수 있다는 점, 비밀번호에 *를 지정하면 프롬프트에서 입력할 수 있다는 점, /user로 다른 사용자 이름을 지정할 수 있다는 점, /delete*를 지정하면 모든 네트워크 연결이 해제된다는 점에 대해.  2

  23. Microsoft Learn, Windows Networking Operations. 지속 연결(persistent connection)이 사용자의 로그온 시 시스템에 의해 자동으로 복원되는 네트워크 연결이라는 점에 대해. 

  24. Microsoft Learn, System Error Codes (0-499). ERROR_BAD_NETPATH(53), ERROR_UNEXP_NET_ERR(59), ERROR_NETNAME_DELETED(64), ERROR_SEM_TIMEOUT(121) 각각의 정의에 대해. 

같은 태그를 공유하는 최신 기사입니다. 더 가까운 주제로 지식을 넓힐 수 있습니다.

이 기사와 가까운 토픽 페이지입니다. 기사를 출발점 삼아 관련 서비스와 다른 기사로 이어집니다.

이 기사는 다음 서비스 페이지로 이어집니다. 가까운 입구부터 확인해 주세요.

자주 묻는 질문

이 기사 주제에 대해 상담 시 자주 나오는 질문을 모았습니다.

Windows 서비스에서 네트워크 드라이브(Z:)에 접근할 수 없는 이유는 무엇인가요?
드라이브 문자가 시스템 전체의 것이 아니라 로그온 세션 단위의 것이기 때문입니다. 사용자가 탐색기에서 매핑한 Z:는 그 사용자의 로그온 세션에 속하는 기호일 뿐이며, 다른 로그온 세션에서 동작하는 서비스에서는 보이지 않습니다. 서비스가 사용자 계정으로 동작하는 경우에도 시스템은 서비스용으로 새로운 로그온 세션을 만들기 때문에, 같은 계정이더라도 데스크톱 쪽의 매핑은 이어받지 못합니다. 서비스에서는 \\server\share 형식의 UNC 경로로 접근하는 것이 정답입니다.
LocalSystem으로 동작하는 서비스에서 공유 폴더에 접근하려면 어떻게 해야 하나요?
LocalSystem은 네트워크상에서는 컴퓨터 자격 증명으로 인증됩니다. 도메인 환경이라면 공유 측(공유 사용 권한과 NTFS ACL)에 해당 머신의 컴퓨터 계정(DOMAIN\MACHINE$)에 대한 권한을 부여하면 접근할 수 있습니다. 다만 머신을 교체하면 권한 설정을 다시 해야 하는 등 운영이 번거로우므로, 실무에서는 서비스의 실행 계정을 도메인 계정이나 gMSA(그룹 관리 서비스 계정)로 하고, 그 계정에 공유 측 권한을 부여하는 구성을 권장합니다.
공유 폴더의 파일을 FileSystemWatcher로 감시해도 되나요?
사용할 수는 있지만, 그것만 단독으로 신뢰해서는 안 됩니다. FileSystemWatcher는 네트워크 드라이브나 원격 컴퓨터의 감시를 지원하지만, 변경 알림은 버퍼를 경유해서 전달되기 때문에 알림이 집중되면 버퍼가 넘쳐 이벤트를 놓칠 수 있습니다. 게다가 네트워크 너머의 감시에서는 버퍼 상한이 64KB로 제한됩니다. 알림은 '재스캔의 계기'로 취급하고, 시작 시・에러 시・정기적인 전체 스캔(폴링)을 반드시 병행하는 것이 정석입니다.
네트워크 단절에 강한 파일 연계를 만들려면 어떻게 해야 하나요?
'공유는 느리고, 끊기고, 상대가 없을 수도 있다'를 정상 동작으로 삼아 설계합니다. 구체적으로는 쓰기는 임시 파일명으로 수행하고 close 후에 이름을 바꿔(rename) 공개하며(temp -> rename), 읽기・쓰기는 재시도로 감싸고 일시적인 네트워크 오류와 업무 오류를 구분해서 처리합니다. File.Exists는 접근할 수 없는 경우에도 false를 반환하기 때문에 '파일이 없다'와 '서버에 도달하지 않는다'를 구분할 수 없다는 점에 주의하고, 재처리해도 깨지지 않는 idempotency(멱등성)한 처리로 만들어 두는 것이 최후의 보루가 됩니다.

저자 프로필

기사 저자의 프로필 페이지입니다.

Go Komura

합동회사 코무라소프트 대표

Windows 소프트웨어 개발, 기술 상담, 장애 조사를 중심으로 재현이 어려운 장애 조사와 기존 자산이 남아 있는 프로젝트에 강점이 있습니다.

블로그 목록으로 돌아가기