프로젝트 개요
문서 중앙화 시스템의 Windows 클라이언트 파트입니다. C# WinForms로 SMB 네트워크 드라이브 연결, USB 차단, 화면 잠금, 관리자 소켓 통신을 구현했습니다. Linux 서버 파트는 이전 포스팅(C,C++ 카테고리)을 참고하세요.
GitHub: https://github.com/LEntropy/Document_Management-Failed-
구현한 기능 목록
| 프로젝트 | 기능 | 상태 |
|---|---|---|
| smbEx01 / smbEx02 | Samba 네트워크 드라이브 연결/해제 | ✅ 동작 |
| UsbTest | USB 저장장치 차단/허용 (레지스트리) | ✅ 동작 |
| ScreenLock01 | 화면 잠금 (전체 화면 오버레이) | ✅ 동작 |
| SocketEx01 / My_Client / My_Server | TCP 소켓 클라이언트-서버 통신 | ✅ 동작 |
| DB_conn | MariaDB 연결 테스트 | ✅ 동작 |
| Admin Ex01 | 관리자 UI 통합 (회원관리 + 원격제어) | ⚠️ 부분 동작 |
| ClientTest | 클라이언트 통합 (SMB+USB+잠금+소켓) | ❌ 통합 미완 |
구현 1 - SMB 네트워크 드라이브 연결 (smbEx01, smbEx02)
Windows API WNetUseConnection을 P/Invoke로 호출하여 Samba 서버에 네트워크 드라이브를 연결합니다.
// NetConn.cs
[DllImport("mpr.dll", CharSet = CharSet.Auto)]
public static extern int WNetUseConnection(
IntPtr hwndOwner,
[MarshalAs(UnmanagedType.Struct)] ref NETRESOURCE lpNetResource,
string lpPassword,
string lpUserID,
uint dwFlags,
StringBuilder lpAccessName,
ref int lpBufferSize,
out uint lpResult);
public int TryConnectNetwork(string remotePath, string userID, string pwd)
{
int capacity = 1028;
uint resultFlags = 0;
StringBuilder sb = new StringBuilder(capacity);
NetResource.dwType = 1; // RESOURCETYPE_DISK
NetResource.IpLocalName = null; // 드라이브 문자 자동 할당
NetResource.IpRemoteName = remotePath; // \\192.168.0.24\share
NetResource.IpProvider = null;
return WNetUseConnection(IntPtr.Zero, ref NetResource,
pwd, userID, 0, sb, ref capacity, out resultFlags);
}
// 드라이브 연결 해제
[DllImport("mpr.dll")]
public static extern int WNetCancelConnection2A(string lpName, int dwFlags, int fForce);
public void DisconnectNetwork()
{
WNetCancelConnection2A(NetResource.IpRemoteName, 1, 0);
}
구현 2 - USB 차단/허용 (UsbTest, ClientTest)
Windows 레지스트리의 USBSTOR 서비스 시작 값을 변경하여 USB 저장장치를 차단하거나 허용합니다.
// USB_con.cs / MainForm.cs
private RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(
@"SYSTEMCurrentControlSetservicesUSBSTOR", true); // true = 쓰기 허용
// USB 차단 (Start 값을 4로 설정)
private void BlockUsb()
{
registryKey.SetValue("Start", 4); // 4 = 비활성화
// USB 드라이브가 즉시 사라지지 않으므로 재시작 또는 장치 재연결 필요
}
// USB 허용 (Start 값을 3으로 설정)
private void AllowUsb()
{
registryKey.SetValue("Start", 3); // 3 = 수동 시작 (정상)
}
⚠️ 레지스트리 쓰기는 관리자 권한이 필요합니다. UAC 설정 또는 manifest에서 권한을 요청해야 합니다.
구현 3 - 화면 잠금 (ScreenLock01)
관리자 명령을 받으면 전체 화면을 덮는 오버레이 폼을 띄워 사용자의 입력을 차단합니다.
// WallForm.cs - 화면 잠금 오버레이
public partial class WallForm : Form
{
public WallForm()
{
InitializeComponent();
this.TopMost = true; // 항상 최상위
this.WindowState = FormWindowState.Maximized;
this.FormBorderStyle = FormBorderStyle.None;
this.BackColor = Color.Black;
this.Opacity = 0.9;
// Alt+F4, Alt+Tab 등 단축키 차단
this.KeyPreview = true;
this.KeyDown += WallForm_KeyDown;
}
private void WallForm_KeyDown(object sender, KeyEventArgs e)
{
// 모든 키 입력 무시
e.Handled = true;
e.SuppressKeyPress = true;
}
}
// MainForm.cs - 화면 잠금/해제
// WindowsHelper.cs로 잠금 관련 Windows API 래핑
private WindowsHelper helper;
private void lockButton_Click(object sender, EventArgs e)
{
WallForm wall = new WallForm();
wall.Show();
}
private void unlockButton_Click(object sender, EventArgs e)
{
// 관리자 인증 후 잠금 해제
helper.UnlockScreen();
}
구현 4 - TCP 소켓 통신 (SocketEx01 / My_Client / My_Server)
관리자 앱(서버)이 클라이언트에 명령(USB 차단, 화면 잠금 등)을 전송합니다.
관리자 앱 (서버 역할 - Admin Ex01)
// Form1.cs - 관리자가 클라이언트의 연결을 기다림
string Server_ip = "192.168.0.24";
string Server_port = "5000";
private void connect() // 별도 스레드에서 실행
{
TcpListener listener = new TcpListener(
IPAddress.Parse(Server_ip), int.Parse(Server_port));
listener.Start();
TcpClient client = listener.AcceptTcpClient(); // 클라이언트 접속 대기
StreamReader sr = new StreamReader(client.GetStream());
StreamWriter sw = new StreamWriter(client.GetStream());
sw.AutoFlush = true;
while (client.Connected)
{
string data = sr.ReadLine();
Alram_data(data); // 수신 데이터 처리 (USB 경고 등)
}
}
클라이언트 (My_Client)
// Form1.cs - 관리자 서버에 접속
TcpClient tcpClient = new TcpClient();
tcpClient.Connect("192.168.0.24", 5000);
StreamReader sr = new StreamReader(tcpClient.GetStream());
StreamWriter sw = new StreamWriter(tcpClient.GetStream());
sw.AutoFlush = true;
// 관리자 명령 수신 루프
while (tcpClient.Connected)
{
string cmd = sr.ReadLine();
if (cmd == "LOCK") LockScreen();
if (cmd == "USB_OFF") BlockUsb();
if (cmd == "USB_ON") AllowUsb();
}
구현 5 - MariaDB 연결 (DB_conn)
// MySqlConnector 패키지 사용
using MySqlConnector;
public static void ConnectionTest()
{
string connStr = "Server=192.168.0.24;Port=3307;Database=my_site;" +
"Uid=root;Pwd=security;";
using var conn = new MySqlConnection(connStr);
conn.Open();
Console.WriteLine("MariaDB 연결 성공!");
}
왜 실패했나 - 프로젝트 실패 원인 분석
각 기능별 예제는 모두 동작했지만, 다음 이유로 최종 통합에 실패했습니다.
1. 기술 범위가 너무 광범위했음
하나의 프로젝트에 너무 많은 기술이 혼재했습니다.
- Linux C (inotify, OpenSSL, MySQL, Samba)
- Windows C# (WinForms, P/Invoke, Registry, Socket, MariaDB)
- 네트워크 설계 (SMB 프로토콜, TCP 소켓)
각 기술을 따로 학습하며 예제를 만들었지만, 이를 하나로 묶는 설계가 부족했습니다.
2. 통합 설계 부재
기능별로 독립된 예제 프로젝트를 만들었지만, 최종 통합 아키텍처가 명확하지 않았습니다.
- ClientTest가 통합을 시도했지만 SMB 연결 + USB 차단 + 화면잠금 + 소켓 통신을 하나의 폼에서 관리하는 상태 관리가 복잡했음
- 관리자 앱이 서버인지 클라이언트인지 역할이 혼재 (Admin Ex01이 TcpListener를 열고 클라이언트 접속을 기다림)
3. 암호화 키 관리 문제
Linux 서버에서 생성된 Key/IV를 Windows 클라이언트가 복호화할 때 어떻게 가져올지 설계가 없었습니다. DB에 Key/IV를 저장했지만 클라이언트에서 파일을 열 때 자동으로 복호화하는 투명 암호화 레이어 구현이 너무 복잡했습니다.
4. 환경 구성의 어려움
- Linux(Ubuntu) + Windows 혼합 환경 테스트가 번거로웠음
- Samba 권한 설정, MariaDB 외부 접속 허용, 방화벽 설정 등 인프라 작업이 많았음
- Visual Studio에서 Linux C 코드를 직접 빌드·테스트 불가
배운 점 및 개선 방향
| 항목 | 내용 |
|---|---|
| 시작 전 설계 | 기능 목록보다 데이터 흐름(파일 → 암호화 → 저장 → 클라이언트 접근)을 먼저 설계했어야 함 |
| 범위 축소 | 처음부터 "SMB + 자동 암호화"만 먼저 완성 후 USB 차단 등 추가 기능을 붙였어야 함 |
| Key 관리 | 파일별 Key/IV를 DB에 저장하는 것까지는 맞았으나, 클라이언트 투명 복호화 레이어 설계가 필요 |
| 테스트 환경 | Docker로 Linux 환경을 Windows에서 빠르게 재현할 수 있었을 것 |
'勉強 > C#' 카테고리의 다른 글
| 문서 중앙화 DLP/ECM - C# KmsClient 구현 (RSA+AES 하이브리드 암호화, .enc 자동 복호화 열기, 저장 감지 재암호화) (0) | 2026.06.02 |
|---|