diff --git a/ControlAgent/ControlAgent.csproj b/ControlAgent/ControlAgent.csproj
new file mode 100644
index 0000000..be1abb8
--- /dev/null
+++ b/ControlAgent/ControlAgent.csproj
@@ -0,0 +1,26 @@
+
+
+
+ WinExe
+ net10.0-windows
+ enable
+ true
+ enable
+
+
+
+
+ True
+ True
+ Resources.resx
+
+
+
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+
+
\ No newline at end of file
diff --git a/ControlAgent/Form1.Designer.cs b/ControlAgent/Form1.Designer.cs
new file mode 100644
index 0000000..d2a199b
--- /dev/null
+++ b/ControlAgent/Form1.Designer.cs
@@ -0,0 +1,66 @@
+namespace ControlAgent
+{
+ partial class Form1
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ lblPCName = new Label();
+ lblMac = new Label();
+ SuspendLayout();
+ //
+ // lblPCName
+ //
+ lblPCName.Location = new Point(226, 57);
+ lblPCName.Name = "lblPCName";
+ lblPCName.Size = new Size(219, 39);
+ lblPCName.TabIndex = 0;
+ //
+ // lblMac
+ //
+ lblMac.Location = new Point(226, 141);
+ lblMac.Name = "lblMac";
+ lblMac.Size = new Size(219, 39);
+ lblMac.TabIndex = 1;
+ //
+ // Form1
+ //
+ AutoScaleDimensions = new SizeF(9F, 20F);
+ AutoScaleMode = AutoScaleMode.Font;
+ ClientSize = new Size(800, 450);
+ Controls.Add(lblMac);
+ Controls.Add(lblPCName);
+ Name = "Form1";
+ Text = "Form1";
+ ResumeLayout(false);
+ }
+
+ #endregion
+
+ private Label lblPCName;
+ private Label lblMac;
+ }
+}
\ No newline at end of file
diff --git a/ControlAgent/Form1.cs b/ControlAgent/Form1.cs
new file mode 100644
index 0000000..5e220e8
--- /dev/null
+++ b/ControlAgent/Form1.cs
@@ -0,0 +1,116 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Net;
+using System.Net.NetworkInformation;
+using System.Net.Sockets;
+using System.Text;
+using System.Windows.Forms;
+
+namespace ControlAgent
+{
+ public partial class Form1 : Form
+ {
+ private bool _isAgentRunning = true;
+
+ public Form1()
+ {
+ InitializeComponent();
+
+ // 백그라운드 태스크 형태로 서버 감지 및 수신 스레드 기동 (UI 먹통 현상 방지)
+ Task.Run(() => StartAgentTask());
+ }
+
+ private void StartAgentTask()
+ {
+ while (_isAgentRunning)
+ {
+ try
+ {
+ using (TcpClient client = new TcpClient())
+ {
+ var result = client.BeginConnect("192.168.219.47", 9999, null, null);
+ bool success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5));
+
+ if (success)
+ {
+ client.EndConnect(result);
+ using (NetworkStream stream = client.GetStream())
+ using (System.IO.StreamReader reader = new System.IO.StreamReader(stream, Encoding.UTF8))
+ {
+ // 1. 연결되자마자 MAC 주소 송신
+ string myMac = GetMacAddress() + "\n";
+ byte[] macBytes = Encoding.UTF8.GetBytes(myMac);
+ stream.Write(macBytes, 0, macBytes.Length);
+ stream.Flush();
+
+ // 2. 서버로부터 명령/데이터 대기 (ReadLine 사용으로 안정성 확보)
+ while (client.Connected)
+ {
+ string command = reader.ReadLine(); // 데이터가 들어올 때까지 여기서 대기
+ if (string.IsNullOrEmpty(command)) break; // 연결이 끊기면 루프 탈출
+ // 명령 처리
+ // 에이전트 코드의 command == "STOP" 내부를 수정
+ if (command == "STOP")
+ {
+ // /f 옵션(강제 종료)과 /t 0(즉시)을 추가하고 절대 경로로 실행
+ System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo();
+ psi.FileName = "cmd.exe";
+ psi.Arguments = "/c shutdown /s /f /t 0"; // /f가 강제 종료 옵션입니다.
+ psi.CreateNoWindow = true;
+ psi.UseShellExecute = false;
+
+ System.Diagnostics.Process.Start(psi);
+
+ _isAgentRunning = false;
+ break;
+ }
+ else
+ {
+ // 데이터 전송 테스트 수신 시 처리
+ MessageBox.Show("서버 메시지 수신: " + command);
+ }
+ }
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine("에이전트 루프 오류: " + ex.Message);
+ }
+
+ if (_isAgentRunning) Thread.Sleep(5000); // 5초 대기 후 재연결
+ }
+ }
+
+ // MAC 물리 주소 자동 추출 내부 함수
+ public string GetMacAddress()
+ {
+ foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces())
+ {
+ // 가상 장치 필터링 및 오프라인 장치 필터링 수행
+ if (ni.NetworkInterfaceType != NetworkInterfaceType.Loopback &&
+ ni.NetworkInterfaceType != NetworkInterfaceType.Tunnel &&
+ ni.OperationalStatus == OperationalStatus.Up)
+ {
+ string mac = ni.GetPhysicalAddress().ToString();
+ if (!string.IsNullOrEmpty(mac))
+ {
+ return mac; // 수집 완료
+ }
+ }
+ }
+ return "MAC Not Found";
+ }
+
+ public string GetMyInfo()
+ {
+ string pcName = Environment.MachineName;
+ string mac = GetMacAddress();
+ return $"{pcName}|{mac}";
+ }
+ }
+}
\ No newline at end of file
diff --git a/ControlAgent/Form1.resx b/ControlAgent/Form1.resx
new file mode 100644
index 0000000..8b2ff64
--- /dev/null
+++ b/ControlAgent/Form1.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/ControlAgent/Program.cs b/ControlAgent/Program.cs
new file mode 100644
index 0000000..fbd914f
--- /dev/null
+++ b/ControlAgent/Program.cs
@@ -0,0 +1,17 @@
+namespace ControlAgent
+{
+ internal static class Program
+ {
+ ///
+ /// The main entry point for the application.
+ ///
+ [STAThread]
+ static void Main()
+ {
+ // To customize application configuration such as set high DPI settings or default font,
+ // see https://aka.ms/applicationconfiguration.
+ ApplicationConfiguration.Initialize();
+ Application.Run(new Form1());
+ }
+ }
+}
\ No newline at end of file
diff --git a/ControlAgent/Properties/Resources.Designer.cs b/ControlAgent/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..d5904cf
--- /dev/null
+++ b/ControlAgent/Properties/Resources.Designer.cs
@@ -0,0 +1,83 @@
+//------------------------------------------------------------------------------
+//
+// 이 코드는 도구를 사용하여 생성되었습니다.
+// 런타임 버전:4.0.30319.42000
+//
+// 파일 내용을 변경하면 잘못된 동작이 발생할 수 있으며, 코드를 다시 생성하면
+// 이러한 변경 내용이 손실됩니다.
+//
+//------------------------------------------------------------------------------
+
+namespace ControlAgent.Properties {
+ using System;
+
+
+ ///
+ /// 지역화된 문자열 등을 찾기 위한 강력한 형식의 리소스 클래스입니다.
+ ///
+ // 이 클래스는 ResGen 또는 Visual Studio와 같은 도구를 통해 StronglyTypedResourceBuilder
+ // 클래스에서 자동으로 생성되었습니다.
+ // 멤버를 추가하거나 제거하려면 .ResX 파일을 편집한 다음 /str 옵션을 사용하여 ResGen을
+ // 다시 실행하거나 VS 프로젝트를 다시 빌드하십시오.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "18.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// 이 클래스에서 사용하는 캐시된 ResourceManager 인스턴스를 반환합니다.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ControlAgent.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// 이 강력한 형식의 리소스 클래스를 사용하여 모든 리소스 조회에 대해 현재 스레드의 CurrentUICulture 속성을
+ /// 재정의합니다.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// System.Drawing.Bitmap 형식의 지역화된 리소스를 찾습니다.
+ ///
+ internal static System.Drawing.Bitmap 둥근_사각형_회색 {
+ get {
+ object obj = ResourceManager.GetObject("둥근-사각형-회색", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// System.Drawing.Bitmap 형식의 지역화된 리소스를 찾습니다.
+ ///
+ internal static System.Drawing.Bitmap 둥근_사각형_회색1 {
+ get {
+ object obj = ResourceManager.GetObject("둥근-사각형-회색1", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+ }
+}
diff --git a/ControlAgent/Properties/Resources.resx b/ControlAgent/Properties/Resources.resx
new file mode 100644
index 0000000..ceec9ed
--- /dev/null
+++ b/ControlAgent/Properties/Resources.resx
@@ -0,0 +1,127 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+
+ ..\Resources\둥근-사각형-회색.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\둥근-사각형-회색1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
\ No newline at end of file
diff --git a/ControlAgent/Resources/둥근-사각형-회색.png b/ControlAgent/Resources/둥근-사각형-회색.png
new file mode 100644
index 0000000..f4faa43
Binary files /dev/null and b/ControlAgent/Resources/둥근-사각형-회색.png differ
diff --git a/ControlAgent/Resources/둥근-사각형-회색1.png b/ControlAgent/Resources/둥근-사각형-회색1.png
new file mode 100644
index 0000000..a5748c2
Binary files /dev/null and b/ControlAgent/Resources/둥근-사각형-회색1.png differ
diff --git a/ControlServer.slnx b/ControlServer.slnx
new file mode 100644
index 0000000..59c9ac2
--- /dev/null
+++ b/ControlServer.slnx
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/ControlServer/ControlServer.csproj b/ControlServer/ControlServer.csproj
new file mode 100644
index 0000000..9c0f4d4
--- /dev/null
+++ b/ControlServer/ControlServer.csproj
@@ -0,0 +1,31 @@
+
+
+
+ WinExe
+ net10.0-windows
+ enable
+ true
+ enable
+
+
+
+
+
+
+
+
+
+ True
+ True
+ Resources.resx
+
+
+
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+
+
\ No newline at end of file
diff --git a/ControlServer/Form1.Designer.cs b/ControlServer/Form1.Designer.cs
new file mode 100644
index 0000000..ab6a9c9
--- /dev/null
+++ b/ControlServer/Form1.Designer.cs
@@ -0,0 +1,316 @@
+namespace ControlServer
+{
+ partial class Form1
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ DataGridViewCellStyle dataGridViewCellStyle1 = new DataGridViewCellStyle();
+ DataGridViewCellStyle dataGridViewCellStyle8 = new DataGridViewCellStyle();
+ DataGridViewCellStyle dataGridViewCellStyle2 = new DataGridViewCellStyle();
+ DataGridViewCellStyle dataGridViewCellStyle3 = new DataGridViewCellStyle();
+ DataGridViewCellStyle dataGridViewCellStyle4 = new DataGridViewCellStyle();
+ DataGridViewCellStyle dataGridViewCellStyle5 = new DataGridViewCellStyle();
+ DataGridViewCellStyle dataGridViewCellStyle6 = new DataGridViewCellStyle();
+ DataGridViewCellStyle dataGridViewCellStyle7 = new DataGridViewCellStyle();
+ pannGray = new Panel();
+ lblTotCnt = new Label();
+ lblGrayTitle = new Label();
+ pannBlue = new Panel();
+ lblRunningCnt = new Label();
+ lblBlueTitle = new Label();
+ grdTotList = new DataGridView();
+ btnLog = new Button();
+ btnRegister = new Button();
+ btnDataUpdate = new Button();
+ txtSearch = new TextBox();
+ pictureBox1 = new PictureBox();
+ Col0 = new DataGridViewTextBoxColumn();
+ Col1 = new DataGridViewTextBoxColumn();
+ Col2 = new DataGridViewTextBoxColumn();
+ Col3 = new DataGridViewTextBoxColumn();
+ Col4 = new DataGridViewTextBoxColumn();
+ Col5 = new DataGridViewTextBoxColumn();
+ Col8 = new DataGridViewTextBoxColumn();
+ pannGray.SuspendLayout();
+ pannBlue.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)grdTotList).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)pictureBox1).BeginInit();
+ SuspendLayout();
+ //
+ // pannGray
+ //
+ pannGray.Controls.Add(lblTotCnt);
+ pannGray.Controls.Add(lblGrayTitle);
+ pannGray.Location = new Point(435, 76);
+ pannGray.Name = "pannGray";
+ pannGray.Size = new Size(190, 120);
+ pannGray.TabIndex = 0;
+ pannGray.Paint += pannGray_Paint;
+ //
+ // lblTotCnt
+ //
+ lblTotCnt.Font = new Font("휴먼둥근헤드라인", 19.8000011F, FontStyle.Regular, GraphicsUnit.Point, 129);
+ lblTotCnt.ForeColor = SystemColors.HighlightText;
+ lblTotCnt.Location = new Point(0, 56);
+ lblTotCnt.Name = "lblTotCnt";
+ lblTotCnt.Size = new Size(190, 48);
+ lblTotCnt.TabIndex = 1;
+ lblTotCnt.Text = "0대";
+ lblTotCnt.TextAlign = ContentAlignment.MiddleCenter;
+ //
+ // lblGrayTitle
+ //
+ lblGrayTitle.AutoSize = true;
+ lblGrayTitle.Location = new Point(33, 20);
+ lblGrayTitle.Name = "lblGrayTitle";
+ lblGrayTitle.Size = new Size(124, 20);
+ lblGrayTitle.TabIndex = 0;
+ lblGrayTitle.Text = "현재 단말기 대수";
+ lblGrayTitle.TextAlign = ContentAlignment.MiddleCenter;
+ //
+ // pannBlue
+ //
+ pannBlue.Controls.Add(lblRunningCnt);
+ pannBlue.Controls.Add(lblBlueTitle);
+ pannBlue.Location = new Point(725, 76);
+ pannBlue.Name = "pannBlue";
+ pannBlue.Size = new Size(190, 120);
+ pannBlue.TabIndex = 2;
+ pannBlue.Paint += pannBlue_Paint;
+ //
+ // lblRunningCnt
+ //
+ lblRunningCnt.Font = new Font("휴먼둥근헤드라인", 19.8000011F, FontStyle.Regular, GraphicsUnit.Point, 129);
+ lblRunningCnt.ForeColor = SystemColors.HighlightText;
+ lblRunningCnt.Location = new Point(0, 56);
+ lblRunningCnt.Name = "lblRunningCnt";
+ lblRunningCnt.Size = new Size(190, 48);
+ lblRunningCnt.TabIndex = 1;
+ lblRunningCnt.Text = "0대";
+ lblRunningCnt.TextAlign = ContentAlignment.MiddleCenter;
+ //
+ // lblBlueTitle
+ //
+ lblBlueTitle.Location = new Point(0, 20);
+ lblBlueTitle.Name = "lblBlueTitle";
+ lblBlueTitle.Size = new Size(190, 20);
+ lblBlueTitle.TabIndex = 0;
+ lblBlueTitle.Text = "프로그램 실행 대수";
+ lblBlueTitle.TextAlign = ContentAlignment.MiddleCenter;
+ //
+ // grdTotList
+ //
+ dataGridViewCellStyle1.Alignment = DataGridViewContentAlignment.MiddleCenter;
+ dataGridViewCellStyle1.BackColor = SystemColors.ButtonShadow;
+ dataGridViewCellStyle1.Font = new Font("맑은 고딕", 9F);
+ dataGridViewCellStyle1.ForeColor = SystemColors.WindowText;
+ dataGridViewCellStyle1.SelectionBackColor = SystemColors.Highlight;
+ dataGridViewCellStyle1.SelectionForeColor = SystemColors.HighlightText;
+ dataGridViewCellStyle1.WrapMode = DataGridViewTriState.True;
+ grdTotList.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle1;
+ grdTotList.ColumnHeadersHeight = 29;
+ grdTotList.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
+ grdTotList.Columns.AddRange(new DataGridViewColumn[] { Col0, Col1, Col2, Col3, Col4, Col5, Col8 });
+ dataGridViewCellStyle8.Alignment = DataGridViewContentAlignment.MiddleCenter;
+ dataGridViewCellStyle8.BackColor = SystemColors.Window;
+ dataGridViewCellStyle8.Font = new Font("맑은 고딕", 9F);
+ dataGridViewCellStyle8.ForeColor = SystemColors.ControlText;
+ dataGridViewCellStyle8.SelectionBackColor = SystemColors.Highlight;
+ dataGridViewCellStyle8.SelectionForeColor = SystemColors.HighlightText;
+ dataGridViewCellStyle8.WrapMode = DataGridViewTriState.False;
+ grdTotList.DefaultCellStyle = dataGridViewCellStyle8;
+ grdTotList.Location = new Point(159, 308);
+ grdTotList.Name = "grdTotList";
+ grdTotList.RowHeadersWidth = 51;
+ grdTotList.Size = new Size(1000, 417);
+ grdTotList.TabIndex = 3;
+ grdTotList.CellMouseClick += grdTotList_CellMouseClick;
+ //
+ // btnLog
+ //
+ btnLog.Location = new Point(1009, 244);
+ btnLog.Name = "btnLog";
+ btnLog.Size = new Size(150, 44);
+ btnLog.TabIndex = 4;
+ btnLog.Text = "제어 이력 조회";
+ btnLog.UseVisualStyleBackColor = true;
+ btnLog.MouseClick += btnLog_MouseClick;
+ //
+ // btnRegister
+ //
+ btnRegister.Location = new Point(880, 244);
+ btnRegister.Name = "btnRegister";
+ btnRegister.Size = new Size(123, 44);
+ btnRegister.TabIndex = 5;
+ btnRegister.Text = "단말기 등록";
+ btnRegister.UseVisualStyleBackColor = true;
+ btnRegister.MouseClick += btnRegister_MouseClick;
+ //
+ // btnDataUpdate
+ //
+ btnDataUpdate.Location = new Point(750, 244);
+ btnDataUpdate.Name = "btnDataUpdate";
+ btnDataUpdate.Size = new Size(123, 44);
+ btnDataUpdate.TabIndex = 6;
+ btnDataUpdate.Text = "데이터 갱신";
+ btnDataUpdate.UseVisualStyleBackColor = true;
+ btnDataUpdate.MouseClick += btnDataUpdate_MouseClick;
+ //
+ // txtSearch
+ //
+ txtSearch.Location = new Point(159, 244);
+ txtSearch.Multiline = true;
+ txtSearch.Name = "txtSearch";
+ txtSearch.Size = new Size(256, 44);
+ txtSearch.TabIndex = 7;
+ txtSearch.TextAlign = HorizontalAlignment.Center;
+ //
+ // pictureBox1
+ //
+ pictureBox1.Image = Properties.Resources.button_search;
+ pictureBox1.Location = new Point(430, 244);
+ pictureBox1.Name = "pictureBox1";
+ pictureBox1.Size = new Size(44, 44);
+ pictureBox1.TabIndex = 8;
+ pictureBox1.TabStop = false;
+ //
+ // Col0
+ //
+ dataGridViewCellStyle2.Alignment = DataGridViewContentAlignment.MiddleCenter;
+ Col0.DefaultCellStyle = dataGridViewCellStyle2;
+ Col0.Frozen = true;
+ Col0.HeaderText = "단말기명";
+ Col0.MinimumWidth = 6;
+ Col0.Name = "Col0";
+ Col0.Width = 150;
+ //
+ // Col1
+ //
+ dataGridViewCellStyle3.Alignment = DataGridViewContentAlignment.MiddleCenter;
+ Col1.DefaultCellStyle = dataGridViewCellStyle3;
+ Col1.Frozen = true;
+ Col1.HeaderText = "MAC주소";
+ Col1.MinimumWidth = 6;
+ Col1.Name = "Col1";
+ Col1.Width = 200;
+ //
+ // Col2
+ //
+ dataGridViewCellStyle4.Alignment = DataGridViewContentAlignment.MiddleCenter;
+ Col2.DefaultCellStyle = dataGridViewCellStyle4;
+ Col2.Frozen = true;
+ Col2.HeaderText = "IP";
+ Col2.MinimumWidth = 6;
+ Col2.Name = "Col2";
+ Col2.Width = 200;
+ //
+ // Col3
+ //
+ dataGridViewCellStyle5.Alignment = DataGridViewContentAlignment.MiddleCenter;
+ Col3.DefaultCellStyle = dataGridViewCellStyle5;
+ Col3.Frozen = true;
+ Col3.HeaderText = "통신설정";
+ Col3.MinimumWidth = 6;
+ Col3.Name = "Col3";
+ Col3.Width = 125;
+ //
+ // Col4
+ //
+ dataGridViewCellStyle6.Alignment = DataGridViewContentAlignment.MiddleCenter;
+ Col4.DefaultCellStyle = dataGridViewCellStyle6;
+ Col4.Frozen = true;
+ Col4.HeaderText = "프로그램";
+ Col4.MinimumWidth = 6;
+ Col4.Name = "Col4";
+ Col4.Width = 125;
+ //
+ // Col5
+ //
+ dataGridViewCellStyle7.Alignment = DataGridViewContentAlignment.MiddleCenter;
+ Col5.DefaultCellStyle = dataGridViewCellStyle7;
+ Col5.Frozen = true;
+ Col5.HeaderText = "마지막 통신 시간";
+ Col5.MinimumWidth = 6;
+ Col5.Name = "Col5";
+ Col5.Width = 200;
+ //
+ // Col8
+ //
+ Col8.HeaderText = "포트번호";
+ Col8.MinimumWidth = 6;
+ Col8.Name = "Col8";
+ Col8.ReadOnly = true;
+ Col8.Visible = false;
+ Col8.Width = 125;
+ //
+ // Form1
+ //
+ AutoScaleDimensions = new SizeF(9F, 20F);
+ AutoScaleMode = AutoScaleMode.Font;
+ ClientSize = new Size(1357, 737);
+ Controls.Add(pictureBox1);
+ Controls.Add(txtSearch);
+ Controls.Add(btnDataUpdate);
+ Controls.Add(btnRegister);
+ Controls.Add(btnLog);
+ Controls.Add(grdTotList);
+ Controls.Add(pannBlue);
+ Controls.Add(pannGray);
+ Name = "Form1";
+ Text = "Form1";
+ pannGray.ResumeLayout(false);
+ pannGray.PerformLayout();
+ pannBlue.ResumeLayout(false);
+ ((System.ComponentModel.ISupportInitialize)grdTotList).EndInit();
+ ((System.ComponentModel.ISupportInitialize)pictureBox1).EndInit();
+ ResumeLayout(false);
+ PerformLayout();
+ }
+
+ #endregion
+
+ private Panel pannGray;
+ private Panel pannBlue;
+ private Label lblGrayTitle;
+ private Label lblBlueTitle;
+ private Label lblTotCnt;
+ private Label lblRunningCnt;
+ private DataGridView grdTotList;
+ private Button btnLog;
+ private Button btnRegister;
+ private Button btnDataUpdate;
+ private TextBox txtSearch;
+ private PictureBox pictureBox1;
+ private DataGridViewTextBoxColumn Col0;
+ private DataGridViewTextBoxColumn Col1;
+ private DataGridViewTextBoxColumn Col2;
+ private DataGridViewTextBoxColumn Col3;
+ private DataGridViewTextBoxColumn Col4;
+ private DataGridViewTextBoxColumn Col5;
+ private DataGridViewTextBoxColumn Col8;
+ }
+}
diff --git a/ControlServer/Form1.cs b/ControlServer/Form1.cs
new file mode 100644
index 0000000..32c144f
--- /dev/null
+++ b/ControlServer/Form1.cs
@@ -0,0 +1,503 @@
+using System.Drawing.Drawing2D;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+
+namespace ControlServer
+{
+ public partial class Form1 : Form
+ {
+ private List terminalList = new List(); // 리스트 생성
+ private Dictionary _connectedAgents = new Dictionary();
+ private TcpListener _listener;
+ private bool _isRunning = false;
+ private string _connectedIP = "";
+ private System.Windows.Forms.Timer _statusTimer;
+ private System.Windows.Forms.Timer _dataSyncTimer;
+
+ public Form1()
+ {
+ InitializeComponent();
+ this.Load += Form1_Load;
+ pannGray.BackColor = Color.Transparent; // 배경색 초기화
+ pannBlue.BackColor = Color.Transparent; // 배경색 초기화
+
+ grdTotList.RowHeadersVisible = false; // 그리드 자동으로 생성되는 첫 번째 열 제거
+ grdTotList.AllowUserToAddRows = false; // 새 행 입력용 기본 로우 제거
+ grdTotList.EnableHeadersVisualStyles = false; // 헤더 기본 테마 사용 안 함
+ grdTotList.ColumnHeadersDefaultCellStyle.BackColor = Color.LightGray; // 헤더 배경색
+ grdTotList.ColumnHeadersHeight = 40; // 헤더 높이
+ grdTotList.AllowUserToResizeRows = false; // 행 높이 조절 금지
+ grdTotList.AllowUserToResizeColumns = false; // 열 너비 조절 금지
+ grdTotList.ReadOnly = true; // 읽기 전용
+ grdTotList.ClearSelection();
+
+ txtSearch.PlaceholderText = "검색(단말기명, IP)";
+ }
+
+ // 가짜 데이터 로드용 함수 (테스트용 예시이며 필요 시 구현체 연결)
+ private void LoadSavedTerminals()
+ {
+ lblTotCnt.Text = grdTotList.RowCount.ToString() + "대";
+ }
+
+ // 폼이 화면에 나타날 때 서버를 별도의 통로(Task)로 실행
+ private void Form1_Load(object sender, EventArgs e)
+ {
+ LoadSavedTerminals(); // 기존에 저장된 단말기 데이터 리스트 로드
+ InitStatusTimer(); // 에이전트pc 상태 여부 확인
+
+ if (grdTotList.Rows.Count > 0)
+ {
+ // 등록된 단말기가 있다면 상태 체크 스레드 및 서버 리스너 시작
+ _ = Task.Run(() => StartServer());
+ _ = Task.Run(() => CheckAllAlliveStatus()); // 상시 또는 최초 상태 체크
+ }
+ else
+ {
+ // 등록된 단말기가 하나도 없다면 리스너를 구동하지 않음
+ MessageBox.Show("등록된 단말기가 없어 서버를 대기 상태로 유지합니다. 단말기를 등록해주세요.");
+ }
+ }
+ private void InitStatusTimer()
+ {
+ _statusTimer = new System.Windows.Forms.Timer();
+ _statusTimer.Interval = 5000; // 5초마다 체크
+ _statusTimer.Tick += (s, e) => {
+ CheckAllAlliveStatus();
+ };
+ _statusTimer.Start();
+ }
+
+ // 기존 등록된 단말기들의 현재 On/Off 상태를 체크하는 함수
+ private void CheckAllAlliveStatus()
+ {
+ foreach (DataGridViewRow row in grdTotList.Rows)
+ {
+ if (row.IsNewRow) continue;
+ string ip = row.Cells[2].Value?.ToString();
+ if (string.IsNullOrEmpty(ip)) continue;
+
+ // 현재 서버에 소켓이 활성화되어 연결되어 있는지 확인
+ bool isAlive = false;
+ lock (_connectedAgents)
+ {
+ if (_connectedAgents.ContainsKey(ip))
+ {
+ TcpClient client = _connectedAgents[ip];
+ // 소켓이 연결되어 있고, 실제 연결 상태가 양호한지 체크
+ if (client != null && client.Connected)
+ {
+ isAlive = true;
+ }
+ }
+ }
+
+ // 만약 소켓이 연결 안 되어 있다면 보조 수단으로 원래의 PingTest를 수행해볼 수 있음
+ if (!isAlive)
+ {
+ isAlive = PingTest(ip);
+ }
+
+ this.Invoke(new Action(() => {
+ if (isAlive)
+ {
+ row.Cells[4].Value = "Start";
+ row.Cells[4].Style.BackColor = Color.Green;
+ row.Cells[4].Style.ForeColor = Color.White;
+ }
+ else
+ {
+ row.Cells[4].Value = "Stop";
+ row.Cells[4].Style.BackColor = Color.Red;
+ row.Cells[4].Style.ForeColor = Color.White;
+ }
+ row.Cells[4].Style.Alignment = DataGridViewContentAlignment.MiddleCenter;
+ }));
+ }
+ this.Invoke(new Action(() => UpdateRunningCount()));
+ }
+
+ private bool PingTest(string ip)
+ {
+ if (string.IsNullOrEmpty(ip)) return false;
+ try
+ {
+ using (System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping())
+ {
+ var reply = ping.Send(ip, 1000); // 1초 타임아웃
+ return reply.Status == System.Net.NetworkInformation.IPStatus.Success;
+ }
+ }
+ catch { return false; }
+ }
+
+ // 서버 시작 함수
+ private async Task StartServer()
+ {
+ try
+ {
+ if (_isRunning) return; // 이미 실행 중이면 중복 방지
+
+ _listener = new TcpListener(IPAddress.Any, 9999);
+ _listener.Start();
+ MessageBox.Show("서버 연결 중...");
+ _isRunning = true;
+
+ while (_isRunning)
+ {
+ // 에이전트의 접속을 비동기로 대기
+ TcpClient client = await _listener.AcceptTcpClientAsync();
+
+ // 에이전트 접속 처리 핸들러 실행
+ _ = Task.Run(() => HandleAgent(client));
+ }
+ }
+ catch (Exception ex)
+ {
+ // 리스너가 중단되었을 때의 예외 처리 제외 처리
+ if (_isRunning)
+ {
+ MessageBox.Show("서버 구동 오류: " + ex.Message);
+ }
+ }
+ }
+
+ // 에이전트에서 데이터 받기
+ private void HandleAgent(TcpClient client)
+ {
+ try
+ {
+ string clientIP = ((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString();
+
+ // using을 쓰지 않고 직접 스트림과 리더를 생성(함수가 끝나도 닫히지 않게)
+ NetworkStream stream = client.GetStream();
+ System.IO.StreamReader reader = new System.IO.StreamReader(stream, Encoding.UTF8);
+
+ // 에이전트가 보낸 첫 줄(MAC 주소)
+ string receivedMac = reader.ReadLine();
+
+ if (!string.IsNullOrEmpty(receivedMac))
+ {
+ this.Invoke(new Action(() => {
+ // 기존 연결이 있다면 안전하게 닫고 교체
+ if (_connectedAgents.ContainsKey(clientIP))
+ {
+ try { _connectedAgents[clientIP].Close(); } catch { }
+ }
+
+ _connectedAgents[clientIP] = client; // 소켓 유지
+ UpdateAgentStatusByMac(receivedMac, clientIP);
+ }));
+
+ // 서버 소켓이 닫히거나 에이전트가 끊어질 때까지
+ // 이 스레드가 종료되지 않고 백그라운드에서 계속 대기하도록 루프를 돌려줌
+ // (에이전트로부터 추가적인 메시지를 받을 때도 여기서 처리 가능)
+ while (client.Connected)
+ {
+ // 에이전트가 보낸 데이터가 없다면 여기서 대기
+ // 에이전트가 연결을 끊으면 null이 들어와 루프를 빠져나감
+ string agentMsg = reader.ReadLine();
+ if (agentMsg == null) break;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine("서버 핸들러 오류: " + ex.Message);
+ }
+ finally
+ {
+ // 연결이 최종적으로 끊기면 딕셔너리에서 제거 및 리소스 정리
+ try
+ {
+ string clientIP = ((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString();
+ lock (_connectedAgents)
+ {
+ if (_connectedAgents.ContainsKey(clientIP))
+ {
+ _connectedAgents.Remove(clientIP);
+ }
+ }
+ }
+ catch { }
+ client.Close();
+ }
+ }
+
+ // MAC 주소를 기반으로 에이전트 매칭 및 상태 업데이트
+ private void UpdateAgentStatusByMac(string clientMac, string clientIP)
+ {
+ // 수신된 MAC에서 불필요한 문자 제거
+ string cleanClientMac = clientMac.Replace("-", "").Replace(":", "").Replace(" ", "").ToUpper().Trim();
+
+ bool isMatched = false;
+
+ this.Invoke(new Action(() => {
+ foreach (DataGridViewRow row in grdTotList.Rows)
+ {
+ string gridIp = row.Cells[2].Value.ToString();
+
+ if (gridIp == clientIP)
+ {
+ row.Cells[1].Value = cleanClientMac;
+ row.Cells[4].Value = "Start";
+ row.Cells[4].Style.BackColor = Color.Green;
+ row.Cells[4].Style.ForeColor = Color.White;
+ row.Cells[5].Value = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
+
+ isMatched = true;
+ break;
+ }
+ }
+
+ if (!isMatched)
+ {
+ Console.WriteLine($"매칭 실패! 수신된 MAC: {cleanClientMac}");
+ }
+
+ UpdateRunningCount();
+ }));
+ }
+
+ // 상단의 프로그램 실행 대수 갱신용 공통 메서드
+ private void UpdateRunningCount()
+ {
+ int startCount = 0;
+ foreach (DataGridViewRow row in grdTotList.Rows)
+ {
+ if (row.IsNewRow) continue;
+ if (row.Cells[4].Value?.ToString() == "Start")
+ {
+ startCount++;
+ }
+ }
+ lblRunningCnt.Text = startCount.ToString() + "대";
+ }
+
+ private void btnRegister_MouseClick(object sender, MouseEventArgs e)
+ {
+ // 단말기 등록 팝업 호출
+ Form2 form = new Form2();
+
+ if (form.ShowDialog() == DialogResult.OK)
+ {
+ TerminalInfo data = form.TerminalData;
+
+ grdTotList.Rows.Add(
+ data.TerminalName, // 단말기명
+ data.Mac, // MAC 주소
+ data.IP, // IP
+ "설정", // 통신설정 버튼
+ "Stop", // 기본 상태
+ DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
+ data.Port // 포트번호
+ );
+
+ int rowIndex = grdTotList.Rows.Count - 1;
+
+ // 프로그램 열 스타일 지정
+ DataGridViewCell cell4 = grdTotList.Rows[rowIndex].Cells[4];
+ cell4.Style.BackColor = Color.Red;
+ cell4.Style.ForeColor = Color.White;
+ cell4.Style.Alignment = DataGridViewContentAlignment.MiddleCenter;
+
+ // 통신설정 열 스타일 지정
+ DataGridViewCell cell3 = grdTotList.Rows[rowIndex].Cells[3];
+ cell3.Style.BackColor = Color.LightGray;
+ cell3.Style.ForeColor = Color.Black;
+ cell3.Style.Alignment = DataGridViewContentAlignment.MiddleCenter;
+
+ // 현재 단말기 개수 업데이트
+ lblTotCnt.Text = grdTotList.RowCount.ToString() + "대";
+
+ // 단말 등록 완료 후 리스너가 구동 중이 아니었다면 리스너 최초 구동 개시
+ if (!_isRunning)
+ {
+ _ = Task.Run(() => StartServer());
+ }
+
+ // 기접속된 IP가 있는 장치라면 바로 연동 매칭
+ if (!string.IsNullOrEmpty(_connectedIP) && _connectedIP == data.IP)
+ {
+ UpdateAgentStatusByMac(data.Mac, data.IP);
+ }
+ }
+ }
+
+ private void btnDataUpdate_MouseClick(object sender, MouseEventArgs e)
+ {
+ // 1. 메시지 전송
+ SendDataToAllAgents("데이터 전송 테스트(수동)");
+
+ // 2. 기존 로직
+ Popup popup = new Popup("전체 단말기에 데이터 전송을 시도했습니다.");
+ popup.ShowDialog();
+ CheckAllAlliveStatus();
+ }
+
+ private void btnLog_MouseClick(object sender, MouseEventArgs e)
+ {
+ Form4 form = new Form4();
+ form.Show();
+ }
+
+ private void grdTotList_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
+ {
+ grdTotList.ClearSelection();
+
+ // 헤더 클릭 방지
+ if (e.RowIndex < 0) return;
+
+ // 통신설정 버튼 열 클릭 시
+ if (e.ColumnIndex == 3)
+ {
+ var row = grdTotList.Rows[e.RowIndex];
+ string TerminalName = row.Cells[0].Value?.ToString() ?? "";
+ string TerminalIp = row.Cells[2].Value?.ToString() ?? "";
+
+ Form3 form = new Form3(TerminalName, TerminalIp);
+ form.ShowDialog();
+ }
+ // 프로그램 작동 제어 제어 열 클릭 시
+ else if (e.ColumnIndex == 4)
+ {
+ DataGridViewRow row = grdTotList.Rows[e.RowIndex];
+ DataGridViewCell cell4 = row.Cells[4];
+
+ string status = cell4.Value?.ToString() ?? "";
+ string targetIP = row.Cells[2].Value?.ToString() ?? "";
+ string targetMac = row.Cells[1].Value?.ToString() ?? "";
+
+ if (status == "Start")
+ {
+ // 에이전트 PC로 원격 강제 종료 패킷 전달
+ SendStopCommandToAgent(targetIP);
+
+ cell4.Value = "Stop";
+ cell4.Style.BackColor = Color.Red;
+ cell4.Style.ForeColor = Color.White;
+ }
+ else
+ {
+ // WOL 매직 패킷 송신
+ if (!string.IsNullOrEmpty(targetMac))
+ {
+ SendWakeOnLan(targetMac);
+
+ cell4.Value = "Start";
+ cell4.Style.BackColor = Color.Green;
+ cell4.Style.ForeColor = Color.White;
+ }
+ else
+ {
+ MessageBox.Show("등록된 MAC 주소가 없습니다.");
+ }
+ }
+
+ cell4.Style.Alignment = DataGridViewContentAlignment.MiddleCenter;
+ UpdateRunningCount();
+ }
+ }
+
+ // [원격 끄기 구현] 소켓 스트림 연동을 위한 에이전트 대상 종료 전송 함수
+ private void SendStopCommandToAgent(string ip)
+ {
+ try
+ {
+ if (_connectedAgents.ContainsKey(ip))
+ {
+ TcpClient client = _connectedAgents[ip];
+ if (client.Connected)
+ {
+ // 중요: 뒤에 "\n"을 추가하여 에이전트의 ReadLine()이 끝을 인식하게 합니다.
+ byte[] msg = Encoding.UTF8.GetBytes("STOP\n");
+ client.GetStream().Write(msg, 0, msg.Length);
+ client.GetStream().Flush();
+ }
+ }
+ else
+ {
+ MessageBox.Show("에이전트가 서버에 연결되어 있지 않습니다.");
+ }
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show("종료 명령 전송 실패: " + ex.Message);
+ }
+ }
+
+ // WOL 매직 패킷 전송 함수
+ private void SendWakeOnLan(string macAddress)
+ {
+ try
+ {
+ string cleanMac = macAddress.Replace("-", "").Replace(":", "").Replace(" ", "").Trim();
+
+ if (cleanMac.Length != 12)
+ {
+ MessageBox.Show("올바른 MAC 주소 형식이 아닙니다.");
+ return;
+ }
+
+ byte[] bytes = new byte[102];
+
+ for (int i = 0; i < 6; i++)
+ {
+ bytes[i] = 0xFF;
+ }
+
+ byte[] macBytes = new byte[6];
+ for (int i = 0; i < 6; i++)
+ {
+ macBytes[i] = Convert.ToByte(cleanMac.Substring(i * 2, 2), 16);
+ }
+
+ for (int i = 1; i <= 16; i++)
+ {
+ Array.Copy(macBytes, 0, bytes, i * 6, 6);
+ }
+
+ using (UdpClient client = new UdpClient())
+ {
+ client.Connect(IPAddress.Parse("255.255.255.255"), 9);
+ client.Send(bytes, bytes.Length);
+ }
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show("WOL 전송 실패: " + ex.Message);
+ }
+ }
+
+ private void SendDataToAllAgents(string message)
+ {
+ // 메시지 끝에 \n을 붙여서 에이전트가 ReadLine()으로 잘 읽게함
+ byte[] data = Encoding.UTF8.GetBytes(message + "\n");
+
+ lock (_connectedAgents) // 여러 스레드에서 접근할 수 있으므로 lock 사용
+ {
+ foreach (var kvp in _connectedAgents)
+ {
+ try
+ {
+ TcpClient client = kvp.Value;
+ if (client != null && client.Connected)
+ {
+ NetworkStream stream = client.GetStream();
+ stream.Write(data, 0, data.Length);
+ stream.Flush();
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"전송 실패 ({kvp.Key}): {ex.Message}");
+ }
+ }
+ }
+ }
+
+ private void pannGray_Paint(object sender, PaintEventArgs e) { }
+ private void pannBlue_Paint(object sender, PaintEventArgs e) { }
+ }
+}
\ No newline at end of file
diff --git a/ControlServer/Form1.resx b/ControlServer/Form1.resx
new file mode 100644
index 0000000..d7de2eb
--- /dev/null
+++ b/ControlServer/Form1.resx
@@ -0,0 +1,141 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
\ No newline at end of file
diff --git a/ControlServer/Form2.Designer.cs b/ControlServer/Form2.Designer.cs
new file mode 100644
index 0000000..51f9174
--- /dev/null
+++ b/ControlServer/Form2.Designer.cs
@@ -0,0 +1,151 @@
+namespace ControlServer
+{
+ partial class Form2
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ lbl0 = new Label();
+ lbl1 = new Label();
+ txtBoxName = new TextBox();
+ txtBoxIP = new TextBox();
+ btnRegister = new Button();
+ btnCancel = new Button();
+ txtBoxPort = new TextBox();
+ lbl5 = new Label();
+ SuspendLayout();
+ //
+ // lbl0
+ //
+ lbl0.BackColor = SystemColors.ControlDark;
+ lbl0.BorderStyle = BorderStyle.FixedSingle;
+ lbl0.Location = new Point(277, 106);
+ lbl0.Name = "lbl0";
+ lbl0.Size = new Size(293, 50);
+ lbl0.TabIndex = 0;
+ lbl0.Text = "단말기명";
+ lbl0.TextAlign = ContentAlignment.MiddleLeft;
+ //
+ // lbl1
+ //
+ lbl1.BackColor = SystemColors.ControlDark;
+ lbl1.BorderStyle = BorderStyle.FixedSingle;
+ lbl1.Location = new Point(277, 156);
+ lbl1.Name = "lbl1";
+ lbl1.Size = new Size(293, 50);
+ lbl1.TabIndex = 1;
+ lbl1.Text = "IP";
+ lbl1.TextAlign = ContentAlignment.MiddleLeft;
+ //
+ // txtBoxName
+ //
+ txtBoxName.Location = new Point(572, 106);
+ txtBoxName.Multiline = true;
+ txtBoxName.Name = "txtBoxName";
+ txtBoxName.Size = new Size(507, 50);
+ txtBoxName.TabIndex = 4;
+ //
+ // txtBoxIP
+ //
+ txtBoxIP.Location = new Point(572, 156);
+ txtBoxIP.Multiline = true;
+ txtBoxIP.Name = "txtBoxIP";
+ txtBoxIP.Size = new Size(507, 50);
+ txtBoxIP.TabIndex = 5;
+ //
+ // btnRegister
+ //
+ btnRegister.BackColor = SystemColors.Desktop;
+ btnRegister.Font = new Font("맑은 고딕", 10.2F, FontStyle.Bold, GraphicsUnit.Point, 129);
+ btnRegister.ForeColor = SystemColors.Window;
+ btnRegister.Location = new Point(460, 291);
+ btnRegister.Name = "btnRegister";
+ btnRegister.Size = new Size(174, 56);
+ btnRegister.TabIndex = 9;
+ btnRegister.Text = "등록";
+ btnRegister.UseVisualStyleBackColor = false;
+ btnRegister.MouseClick += btnRegister_MouseClick;
+ //
+ // btnCancel
+ //
+ btnCancel.Font = new Font("맑은 고딕", 10.2F, FontStyle.Bold, GraphicsUnit.Point, 129);
+ btnCancel.Location = new Point(710, 291);
+ btnCancel.Name = "btnCancel";
+ btnCancel.Size = new Size(174, 56);
+ btnCancel.TabIndex = 10;
+ btnCancel.Text = "취소";
+ btnCancel.UseVisualStyleBackColor = true;
+ btnCancel.MouseClick += btnCancel_MouseClick;
+ //
+ // txtBoxPort
+ //
+ txtBoxPort.Location = new Point(572, 206);
+ txtBoxPort.Multiline = true;
+ txtBoxPort.Name = "txtBoxPort";
+ txtBoxPort.Size = new Size(507, 50);
+ txtBoxPort.TabIndex = 12;
+ //
+ // lbl5
+ //
+ lbl5.BackColor = SystemColors.ControlDark;
+ lbl5.BorderStyle = BorderStyle.FixedSingle;
+ lbl5.Location = new Point(277, 206);
+ lbl5.Name = "lbl5";
+ lbl5.Size = new Size(293, 50);
+ lbl5.TabIndex = 11;
+ lbl5.Text = "Port";
+ lbl5.TextAlign = ContentAlignment.MiddleLeft;
+ //
+ // Form2
+ //
+ AutoScaleDimensions = new SizeF(9F, 20F);
+ AutoScaleMode = AutoScaleMode.Font;
+ ClientSize = new Size(1357, 737);
+ Controls.Add(txtBoxPort);
+ Controls.Add(lbl5);
+ Controls.Add(btnCancel);
+ Controls.Add(btnRegister);
+ Controls.Add(txtBoxIP);
+ Controls.Add(txtBoxName);
+ Controls.Add(lbl1);
+ Controls.Add(lbl0);
+ Name = "Form2";
+ ResumeLayout(false);
+ PerformLayout();
+ }
+
+ #endregion
+
+ private Label lbl0;
+ private Label lbl1;
+ private TextBox txtBoxName;
+ private TextBox txtBoxIP;
+ private Button btnRegister;
+ private Button btnCancel;
+ private TextBox txtBoxPort;
+ private Label lbl5;
+ }
+}
\ No newline at end of file
diff --git a/ControlServer/Form2.cs b/ControlServer/Form2.cs
new file mode 100644
index 0000000..e3e82b9
--- /dev/null
+++ b/ControlServer/Form2.cs
@@ -0,0 +1,65 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Text;
+using System.Windows.Forms;
+
+namespace ControlServer
+{
+ public partial class Form2 : Form
+ {
+ public TerminalInfo TerminalData { get; private set; } = new TerminalInfo();
+
+ public Form2()
+ {
+ InitializeComponent();
+
+ btnRegister.Enabled = false; // 저장버튼 비활성화
+ // 모든 텍스트박스의 값이 변할 때마다 실행될 이벤트 연결
+ txtBoxName.TextChanged += ValidateInputs;
+ txtBoxIP.TextChanged += ValidateInputs;
+ txtBoxPort.TextChanged += ValidateInputs;
+ }
+
+ private void ValidateInputs(object? sender, EventArgs e)
+ {
+ // 모든 텍스트박스가 공백이 아닐 때만 true
+ bool isValid = !string.IsNullOrWhiteSpace(txtBoxName.Text) &&
+ !string.IsNullOrWhiteSpace(txtBoxIP.Text) &&
+ !string.IsNullOrWhiteSpace(txtBoxPort.Text);
+
+ // 저장 버튼 활성화 상태 조절
+ btnRegister.Enabled = isValid;
+ }
+
+ private void btnCancel_MouseClick(object sender, MouseEventArgs e)
+ {
+ // 취소 버튼
+ this.Close();
+ }
+
+ private void btnRegister_MouseClick(object sender, MouseEventArgs e)
+ {
+ // 1. DB 중복 데이터 확인
+
+ // 2. 중복 데이터 없을 경우 DB에 데이터 추가
+ // DB 가져오면 데이터 넘겨주는게 아니라 테이블에 데이터 추가하고 Form1 화면에서 데이터 가져와 리스트 보여주는 형식으로 변경할 예정
+ Popup popup = new Popup("등록되었습니다.");
+
+ if (popup.ShowDialog() == DialogResult.OK)
+ {
+ this.TerminalData = new TerminalInfo
+ {
+ TerminalName = txtBoxName.Text.Trim(),
+ IP = txtBoxIP.Text.Trim(),
+ Port = txtBoxPort.Text.Trim()
+ };
+ }
+
+ this.DialogResult = DialogResult.OK;
+ this.Close();
+ }
+ }
+}
diff --git a/ControlServer/Form2.resx b/ControlServer/Form2.resx
new file mode 100644
index 0000000..8b2ff64
--- /dev/null
+++ b/ControlServer/Form2.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/ControlServer/Form3.Designer.cs b/ControlServer/Form3.Designer.cs
new file mode 100644
index 0000000..aa0e3a8
--- /dev/null
+++ b/ControlServer/Form3.Designer.cs
@@ -0,0 +1,317 @@
+namespace ControlServer
+{
+ partial class Form3
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ lblTerminalName = new Label();
+ lblTerminalIP = new Label();
+ label1 = new Label();
+ label2 = new Label();
+ lbl0 = new Label();
+ label3 = new Label();
+ label4 = new Label();
+ pannUpdate = new Panel();
+ rdoUpdate5m = new RadioButton();
+ rdoUpdate3m = new RadioButton();
+ rdoUpdate1m = new RadioButton();
+ pannStartTime = new Panel();
+ label5 = new Label();
+ txtBoxOnMM = new TextBox();
+ txtBoxOnYY = new TextBox();
+ pannStopTime = new Panel();
+ label6 = new Label();
+ txtBoxOffMM = new TextBox();
+ txtBoxOffYY = new TextBox();
+ btnCancel = new Button();
+ btnUpdate = new Button();
+ pannUpdate.SuspendLayout();
+ pannStartTime.SuspendLayout();
+ pannStopTime.SuspendLayout();
+ SuspendLayout();
+ //
+ // lblTerminalName
+ //
+ lblTerminalName.Font = new Font("맑은 고딕", 9F, FontStyle.Bold, GraphicsUnit.Point, 129);
+ lblTerminalName.Location = new Point(430, 42);
+ lblTerminalName.Name = "lblTerminalName";
+ lblTerminalName.Size = new Size(288, 50);
+ lblTerminalName.TabIndex = 0;
+ lblTerminalName.TextAlign = ContentAlignment.MiddleLeft;
+ //
+ // lblTerminalIP
+ //
+ lblTerminalIP.Location = new Point(430, 118);
+ lblTerminalIP.Name = "lblTerminalIP";
+ lblTerminalIP.Size = new Size(288, 50);
+ lblTerminalIP.TabIndex = 1;
+ lblTerminalIP.TextAlign = ContentAlignment.MiddleLeft;
+ //
+ // label1
+ //
+ label1.Location = new Point(254, 42);
+ label1.Name = "label1";
+ label1.Size = new Size(147, 50);
+ label1.TabIndex = 2;
+ label1.Text = "단말기명";
+ label1.TextAlign = ContentAlignment.MiddleLeft;
+ //
+ // label2
+ //
+ label2.Location = new Point(254, 118);
+ label2.Name = "label2";
+ label2.Size = new Size(147, 50);
+ label2.TabIndex = 3;
+ label2.Text = "IP";
+ label2.TextAlign = ContentAlignment.MiddleLeft;
+ //
+ // lbl0
+ //
+ lbl0.BackColor = SystemColors.ControlDark;
+ lbl0.BorderStyle = BorderStyle.FixedSingle;
+ lbl0.Location = new Point(254, 223);
+ lbl0.Name = "lbl0";
+ lbl0.Size = new Size(159, 50);
+ lbl0.TabIndex = 4;
+ lbl0.Text = "갱신주기";
+ lbl0.TextAlign = ContentAlignment.MiddleLeft;
+ //
+ // label3
+ //
+ label3.BackColor = SystemColors.ControlDark;
+ label3.BorderStyle = BorderStyle.FixedSingle;
+ label3.Location = new Point(254, 273);
+ label3.Name = "label3";
+ label3.Size = new Size(159, 50);
+ label3.TabIndex = 5;
+ label3.Text = "프로그램 ON 시간";
+ label3.TextAlign = ContentAlignment.MiddleLeft;
+ //
+ // label4
+ //
+ label4.BackColor = SystemColors.ControlDark;
+ label4.BorderStyle = BorderStyle.FixedSingle;
+ label4.Location = new Point(254, 323);
+ label4.Name = "label4";
+ label4.Size = new Size(159, 50);
+ label4.TabIndex = 6;
+ label4.Text = "프로그램 OFF 시간";
+ label4.TextAlign = ContentAlignment.MiddleLeft;
+ //
+ // pannUpdate
+ //
+ pannUpdate.BorderStyle = BorderStyle.FixedSingle;
+ pannUpdate.Controls.Add(rdoUpdate5m);
+ pannUpdate.Controls.Add(rdoUpdate3m);
+ pannUpdate.Controls.Add(rdoUpdate1m);
+ pannUpdate.Location = new Point(413, 223);
+ pannUpdate.Name = "pannUpdate";
+ pannUpdate.Size = new Size(356, 50);
+ pannUpdate.TabIndex = 7;
+ //
+ // rdoUpdate5m
+ //
+ rdoUpdate5m.AutoSize = true;
+ rdoUpdate5m.Location = new Point(157, 12);
+ rdoUpdate5m.Name = "rdoUpdate5m";
+ rdoUpdate5m.Size = new Size(53, 24);
+ rdoUpdate5m.TabIndex = 2;
+ rdoUpdate5m.TabStop = true;
+ rdoUpdate5m.Text = "5분";
+ rdoUpdate5m.UseVisualStyleBackColor = true;
+ //
+ // rdoUpdate3m
+ //
+ rdoUpdate3m.AutoSize = true;
+ rdoUpdate3m.Location = new Point(86, 12);
+ rdoUpdate3m.Name = "rdoUpdate3m";
+ rdoUpdate3m.Size = new Size(53, 24);
+ rdoUpdate3m.TabIndex = 1;
+ rdoUpdate3m.TabStop = true;
+ rdoUpdate3m.Text = "3분";
+ rdoUpdate3m.UseVisualStyleBackColor = true;
+ //
+ // rdoUpdate1m
+ //
+ rdoUpdate1m.AutoSize = true;
+ rdoUpdate1m.Location = new Point(16, 12);
+ rdoUpdate1m.Name = "rdoUpdate1m";
+ rdoUpdate1m.Size = new Size(53, 24);
+ rdoUpdate1m.TabIndex = 0;
+ rdoUpdate1m.TabStop = true;
+ rdoUpdate1m.Text = "1분";
+ rdoUpdate1m.UseVisualStyleBackColor = true;
+ //
+ // pannStartTime
+ //
+ pannStartTime.BorderStyle = BorderStyle.FixedSingle;
+ pannStartTime.Controls.Add(label5);
+ pannStartTime.Controls.Add(txtBoxOnMM);
+ pannStartTime.Controls.Add(txtBoxOnYY);
+ pannStartTime.Location = new Point(413, 273);
+ pannStartTime.Name = "pannStartTime";
+ pannStartTime.Size = new Size(356, 50);
+ pannStartTime.TabIndex = 8;
+ //
+ // label5
+ //
+ label5.AutoSize = true;
+ label5.Location = new Point(83, 14);
+ label5.Name = "label5";
+ label5.Size = new Size(12, 20);
+ label5.TabIndex = 2;
+ label5.Text = ":";
+ //
+ // txtBoxOnMM
+ //
+ txtBoxOnMM.Location = new Point(99, 11);
+ txtBoxOnMM.Name = "txtBoxOnMM";
+ txtBoxOnMM.Size = new Size(64, 27);
+ txtBoxOnMM.TabIndex = 1;
+ txtBoxOnMM.TextAlign = HorizontalAlignment.Center;
+ //
+ // txtBoxOnYY
+ //
+ txtBoxOnYY.Location = new Point(16, 11);
+ txtBoxOnYY.Name = "txtBoxOnYY";
+ txtBoxOnYY.Size = new Size(64, 27);
+ txtBoxOnYY.TabIndex = 0;
+ txtBoxOnYY.TextAlign = HorizontalAlignment.Center;
+ //
+ // pannStopTime
+ //
+ pannStopTime.BorderStyle = BorderStyle.FixedSingle;
+ pannStopTime.Controls.Add(label6);
+ pannStopTime.Controls.Add(txtBoxOffMM);
+ pannStopTime.Controls.Add(txtBoxOffYY);
+ pannStopTime.Location = new Point(413, 323);
+ pannStopTime.Name = "pannStopTime";
+ pannStopTime.Size = new Size(356, 50);
+ pannStopTime.TabIndex = 9;
+ //
+ // label6
+ //
+ label6.AutoSize = true;
+ label6.Location = new Point(83, 14);
+ label6.Name = "label6";
+ label6.Size = new Size(12, 20);
+ label6.TabIndex = 5;
+ label6.Text = ":";
+ //
+ // txtBoxOffMM
+ //
+ txtBoxOffMM.Location = new Point(99, 11);
+ txtBoxOffMM.Name = "txtBoxOffMM";
+ txtBoxOffMM.Size = new Size(64, 27);
+ txtBoxOffMM.TabIndex = 4;
+ txtBoxOffMM.TextAlign = HorizontalAlignment.Center;
+ //
+ // txtBoxOffYY
+ //
+ txtBoxOffYY.Location = new Point(16, 11);
+ txtBoxOffYY.Name = "txtBoxOffYY";
+ txtBoxOffYY.Size = new Size(64, 27);
+ txtBoxOffYY.TabIndex = 3;
+ txtBoxOffYY.TextAlign = HorizontalAlignment.Center;
+ //
+ // btnCancel
+ //
+ btnCancel.Font = new Font("맑은 고딕", 10.2F, FontStyle.Bold, GraphicsUnit.Point, 129);
+ btnCancel.Location = new Point(559, 408);
+ btnCancel.Name = "btnCancel";
+ btnCancel.Size = new Size(174, 56);
+ btnCancel.TabIndex = 12;
+ btnCancel.Text = "취소";
+ btnCancel.UseVisualStyleBackColor = true;
+ btnCancel.MouseClick += btnCancel_MouseClick;
+ //
+ // btnUpdate
+ //
+ btnUpdate.BackColor = SystemColors.Desktop;
+ btnUpdate.Font = new Font("맑은 고딕", 10.2F, FontStyle.Bold, GraphicsUnit.Point, 129);
+ btnUpdate.ForeColor = SystemColors.Window;
+ btnUpdate.Location = new Point(309, 408);
+ btnUpdate.Name = "btnUpdate";
+ btnUpdate.Size = new Size(174, 56);
+ btnUpdate.TabIndex = 11;
+ btnUpdate.Text = "수정";
+ btnUpdate.UseVisualStyleBackColor = false;
+ btnUpdate.MouseClick += btnUpdate_MouseClick;
+ //
+ // Form3
+ //
+ AutoScaleDimensions = new SizeF(9F, 20F);
+ AutoScaleMode = AutoScaleMode.Font;
+ ClientSize = new Size(1008, 563);
+ Controls.Add(btnCancel);
+ Controls.Add(btnUpdate);
+ Controls.Add(pannStopTime);
+ Controls.Add(pannStartTime);
+ Controls.Add(pannUpdate);
+ Controls.Add(label4);
+ Controls.Add(label3);
+ Controls.Add(lbl0);
+ Controls.Add(label2);
+ Controls.Add(label1);
+ Controls.Add(lblTerminalIP);
+ Controls.Add(lblTerminalName);
+ Name = "Form3";
+ Text = "Form3";
+ pannUpdate.ResumeLayout(false);
+ pannUpdate.PerformLayout();
+ pannStartTime.ResumeLayout(false);
+ pannStartTime.PerformLayout();
+ pannStopTime.ResumeLayout(false);
+ pannStopTime.PerformLayout();
+ ResumeLayout(false);
+ }
+
+ #endregion
+
+ private Label lblTerminalName;
+ private Label lblTerminalIP;
+ private Label label1;
+ private Label label2;
+ private Label lbl0;
+ private Label label3;
+ private Label label4;
+ private Panel pannUpdate;
+ private Panel pannStartTime;
+ private Panel pannStopTime;
+ private RadioButton rdoUpdate1m;
+ private RadioButton rdoUpdate5m;
+ private RadioButton rdoUpdate3m;
+ private TextBox txtBoxOnYY;
+ private TextBox txtBoxOnMM;
+ private Label label5;
+ private Label label6;
+ private TextBox txtBoxOffMM;
+ private TextBox txtBoxOffYY;
+ private Button btnCancel;
+ private Button btnUpdate;
+ }
+}
\ No newline at end of file
diff --git a/ControlServer/Form3.cs b/ControlServer/Form3.cs
new file mode 100644
index 0000000..7f7b793
--- /dev/null
+++ b/ControlServer/Form3.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Text;
+using System.Windows.Forms;
+
+namespace ControlServer
+{
+ public partial class Form3 : Form
+ {
+ public Form3(string terminalName, string terminalIP) // 매개변수 추가
+ {
+ InitializeComponent();
+
+ // 가져온 데이터를 Form3의 라벨이나 텍스트박스에 표시
+ lblTerminalName.Text = terminalName;
+ lblTerminalIP.Text = terminalIP;
+
+ txtBoxOnYY.TextChanged += ValidateInputs;
+ txtBoxOnMM.TextChanged += ValidateInputs;
+ txtBoxOffYY.TextChanged += ValidateInputs;
+ txtBoxOffMM.TextChanged += ValidateInputs;
+ txtBoxOnYY.PlaceholderText = "YY";
+ txtBoxOnMM.PlaceholderText = "MM";
+ txtBoxOffYY.PlaceholderText = "YY";
+ txtBoxOffMM.PlaceholderText = "MM";
+ }
+
+ private void ValidateInputs(object? sender, EventArgs e)
+ {
+ // 프로그램 시간 조건 체크
+ bool isOnYYEmpty = string.IsNullOrWhiteSpace(txtBoxOnYY.Text);
+ bool isOnMMEmpty = string.IsNullOrWhiteSpace(txtBoxOnMM.Text);
+ bool isOffYYEmpty = string.IsNullOrWhiteSpace(txtBoxOffYY.Text);
+ bool isOffMMEmpty = string.IsNullOrWhiteSpace(@txtBoxOffMM.Text);
+
+ // 둘 다 비어있거나(AND), 둘 다 비어있지 않거나(AND)
+ bool isTimeValid = (isOnYYEmpty && isOnMMEmpty && isOffYYEmpty && isOffMMEmpty) || (!isOnYYEmpty && !isOnMMEmpty && !isOffYYEmpty && !isOffMMEmpty);
+
+ // 저장 버튼 활성화
+ btnUpdate.Enabled = isTimeValid;
+ }
+
+ private void btnCancel_MouseClick(object sender, MouseEventArgs e)
+ {
+ this.Close();
+ }
+
+ private void btnUpdate_MouseClick(object sender, MouseEventArgs e)
+ {
+ // 수정
+ // 수정 시 DB 저장
+ }
+ }
+}
diff --git a/ControlServer/Form3.resx b/ControlServer/Form3.resx
new file mode 100644
index 0000000..8b2ff64
--- /dev/null
+++ b/ControlServer/Form3.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/ControlServer/Form4.Designer.cs b/ControlServer/Form4.Designer.cs
new file mode 100644
index 0000000..674169c
--- /dev/null
+++ b/ControlServer/Form4.Designer.cs
@@ -0,0 +1,166 @@
+namespace ControlServer
+{
+ partial class Form4
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ DataGridViewCellStyle dataGridViewCellStyle7 = new DataGridViewCellStyle();
+ DataGridViewCellStyle dataGridViewCellStyle12 = new DataGridViewCellStyle();
+ DataGridViewCellStyle dataGridViewCellStyle8 = new DataGridViewCellStyle();
+ DataGridViewCellStyle dataGridViewCellStyle9 = new DataGridViewCellStyle();
+ DataGridViewCellStyle dataGridViewCellStyle10 = new DataGridViewCellStyle();
+ DataGridViewCellStyle dataGridViewCellStyle11 = new DataGridViewCellStyle();
+ grdLog = new DataGridView();
+ Col5 = new DataGridViewTextBoxColumn();
+ Col0 = new DataGridViewTextBoxColumn();
+ Col3 = new DataGridViewTextBoxColumn();
+ Col4 = new DataGridViewTextBoxColumn();
+ Col6 = new DataGridViewTextBoxColumn();
+ Col7 = new DataGridViewTextBoxColumn();
+ btnPrev = new Button();
+ ((System.ComponentModel.ISupportInitialize)grdLog).BeginInit();
+ SuspendLayout();
+ //
+ // grdLog
+ //
+ dataGridViewCellStyle7.Alignment = DataGridViewContentAlignment.MiddleCenter;
+ dataGridViewCellStyle7.BackColor = SystemColors.ButtonShadow;
+ dataGridViewCellStyle7.Font = new Font("맑은 고딕", 9F);
+ dataGridViewCellStyle7.ForeColor = SystemColors.WindowText;
+ dataGridViewCellStyle7.SelectionBackColor = SystemColors.Highlight;
+ dataGridViewCellStyle7.SelectionForeColor = SystemColors.HighlightText;
+ dataGridViewCellStyle7.WrapMode = DataGridViewTriState.True;
+ grdLog.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle7;
+ grdLog.ColumnHeadersHeight = 29;
+ grdLog.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
+ grdLog.Columns.AddRange(new DataGridViewColumn[] { Col5, Col0, Col3, Col4, Col6, Col7 });
+ dataGridViewCellStyle12.Alignment = DataGridViewContentAlignment.MiddleCenter;
+ dataGridViewCellStyle12.BackColor = SystemColors.Window;
+ dataGridViewCellStyle12.Font = new Font("맑은 고딕", 9F);
+ dataGridViewCellStyle12.ForeColor = SystemColors.ControlText;
+ dataGridViewCellStyle12.SelectionBackColor = SystemColors.Highlight;
+ dataGridViewCellStyle12.SelectionForeColor = SystemColors.HighlightText;
+ dataGridViewCellStyle12.WrapMode = DataGridViewTriState.False;
+ grdLog.DefaultCellStyle = dataGridViewCellStyle12;
+ grdLog.Location = new Point(164, 87);
+ grdLog.Name = "grdLog";
+ grdLog.RowHeadersWidth = 51;
+ grdLog.Size = new Size(1000, 638);
+ grdLog.TabIndex = 4;
+ //
+ // Col5
+ //
+ dataGridViewCellStyle8.Alignment = DataGridViewContentAlignment.MiddleCenter;
+ Col5.DefaultCellStyle = dataGridViewCellStyle8;
+ Col5.Frozen = true;
+ Col5.HeaderText = "일시";
+ Col5.MinimumWidth = 6;
+ Col5.Name = "Col5";
+ Col5.Width = 220;
+ //
+ // Col0
+ //
+ dataGridViewCellStyle9.Alignment = DataGridViewContentAlignment.MiddleCenter;
+ Col0.DefaultCellStyle = dataGridViewCellStyle9;
+ Col0.Frozen = true;
+ Col0.HeaderText = "단말기명";
+ Col0.MinimumWidth = 6;
+ Col0.Name = "Col0";
+ Col0.Width = 170;
+ //
+ // Col3
+ //
+ dataGridViewCellStyle10.Alignment = DataGridViewContentAlignment.MiddleCenter;
+ Col3.DefaultCellStyle = dataGridViewCellStyle10;
+ Col3.Frozen = true;
+ Col3.HeaderText = "명령 유형";
+ Col3.MinimumWidth = 6;
+ Col3.Name = "Col3";
+ Col3.Width = 125;
+ //
+ // Col4
+ //
+ dataGridViewCellStyle11.Alignment = DataGridViewContentAlignment.MiddleCenter;
+ Col4.DefaultCellStyle = dataGridViewCellStyle11;
+ Col4.Frozen = true;
+ Col4.HeaderText = "수행자";
+ Col4.MinimumWidth = 6;
+ Col4.Name = "Col4";
+ Col4.Width = 125;
+ //
+ // Col6
+ //
+ Col6.Frozen = true;
+ Col6.HeaderText = "결과";
+ Col6.MinimumWidth = 6;
+ Col6.Name = "Col6";
+ Col6.Width = 125;
+ //
+ // Col7
+ //
+ Col7.Frozen = true;
+ Col7.HeaderText = "상세내용";
+ Col7.MinimumWidth = 6;
+ Col7.Name = "Col7";
+ Col7.Width = 285;
+ //
+ // btnPrev
+ //
+ btnPrev.Font = new Font("맑은 고딕", 10.2F, FontStyle.Bold, GraphicsUnit.Point, 129);
+ btnPrev.Location = new Point(164, 12);
+ btnPrev.Name = "btnPrev";
+ btnPrev.Size = new Size(174, 56);
+ btnPrev.TabIndex = 13;
+ btnPrev.Text = "이전";
+ btnPrev.UseVisualStyleBackColor = true;
+ btnPrev.MouseClick += btnPrev_MouseClick;
+ //
+ // Form4
+ //
+ AutoScaleDimensions = new SizeF(9F, 20F);
+ AutoScaleMode = AutoScaleMode.Font;
+ ClientSize = new Size(1357, 737);
+ Controls.Add(btnPrev);
+ Controls.Add(grdLog);
+ Name = "Form4";
+ Text = "Form4";
+ ((System.ComponentModel.ISupportInitialize)grdLog).EndInit();
+ ResumeLayout(false);
+ }
+
+ #endregion
+
+ private DataGridView grdLog;
+ private DataGridViewTextBoxColumn Col5;
+ private DataGridViewTextBoxColumn Col0;
+ private DataGridViewTextBoxColumn Col3;
+ private DataGridViewTextBoxColumn Col4;
+ private DataGridViewTextBoxColumn Col6;
+ private DataGridViewTextBoxColumn Col7;
+ private Button btnPrev;
+ }
+}
\ No newline at end of file
diff --git a/ControlServer/Form4.cs b/ControlServer/Form4.cs
new file mode 100644
index 0000000..3745b0a
--- /dev/null
+++ b/ControlServer/Form4.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Text;
+using System.Windows.Forms;
+
+namespace ControlServer
+{
+ public partial class Form4 : Form
+ {
+ public Form4()
+ {
+ InitializeComponent();
+
+ grdLog.RowHeadersVisible = false; // 그리드 자동으로 생성되는 첫 번째 열 제거
+ grdLog.AllowUserToAddRows = false; // 새 행 입력용 기본 로우 제거
+ grdLog.EnableHeadersVisualStyles = false; // 헤더 기본 테마 사용 안 함
+ grdLog.ColumnHeadersDefaultCellStyle.BackColor = Color.LightGray; // 헤더 배경색
+ grdLog.ColumnHeadersHeight = 40; // 헤더 높이
+ grdLog.RowHeadersVisible = false; // 행 헤더 제거
+ grdLog.AllowUserToAddRows = false; // // 행 추가 금지
+ grdLog.AllowUserToResizeRows = false; // 행 높이 조절 금지
+ grdLog.AllowUserToResizeColumns = false; // 열 너비 조절 금지
+ grdLog.ReadOnly = true; // 읽기 전용
+ grdLog.ClearSelection();
+ }
+
+ private void btnPrev_MouseClick(object sender, MouseEventArgs e)
+ {
+ this.Close();
+ }
+ }
+}
diff --git a/ControlServer/Form4.resx b/ControlServer/Form4.resx
new file mode 100644
index 0000000..37e0ab2
--- /dev/null
+++ b/ControlServer/Form4.resx
@@ -0,0 +1,138 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
+
\ No newline at end of file
diff --git a/ControlServer/Popup.Designer.cs b/ControlServer/Popup.Designer.cs
new file mode 100644
index 0000000..b0c5319
--- /dev/null
+++ b/ControlServer/Popup.Designer.cs
@@ -0,0 +1,82 @@
+namespace ControlServer
+{
+ partial class Popup
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ lblText = new Label();
+ btnOk = new Button();
+ SuspendLayout();
+ //
+ // lblText
+ //
+ lblText.Font = new Font("맑은 고딕", 12F, FontStyle.Regular, GraphicsUnit.Point, 129);
+ lblText.ForeColor = Color.Black;
+ lblText.Location = new Point(71, 50);
+ lblText.Name = "lblText";
+ lblText.Size = new Size(418, 139);
+ lblText.TabIndex = 0;
+ lblText.TextAlign = ContentAlignment.MiddleCenter;
+ //
+ // btnOk
+ //
+ btnOk.BackColor = SystemColors.Desktop;
+ btnOk.Font = new Font("맑은 고딕", 12F, FontStyle.Regular, GraphicsUnit.Point, 129);
+ btnOk.ForeColor = Color.White;
+ btnOk.Location = new Point(119, 235);
+ btnOk.Name = "btnOk";
+ btnOk.Size = new Size(328, 62);
+ btnOk.TabIndex = 1;
+ btnOk.Text = "확인";
+ btnOk.UseVisualStyleBackColor = false;
+ btnOk.MouseClick += btnOk_MouseClick;
+ //
+ // Popup
+ //
+ AutoScaleDimensions = new SizeF(9F, 20F);
+ AutoScaleMode = AutoScaleMode.Font;
+ BackColor = SystemColors.Window;
+ ClientSize = new Size(558, 332);
+ Controls.Add(btnOk);
+ Controls.Add(lblText);
+ ForeColor = Color.Transparent;
+ FormBorderStyle = FormBorderStyle.None;
+ MaximizeBox = false;
+ MinimizeBox = false;
+ Name = "Popup";
+ ShowInTaskbar = false;
+ StartPosition = FormStartPosition.CenterParent;
+ Text = "Popup";
+ ResumeLayout(false);
+ }
+
+ #endregion
+
+ private Label lblText;
+ private Button btnOk;
+ }
+}
\ No newline at end of file
diff --git a/ControlServer/Popup.cs b/ControlServer/Popup.cs
new file mode 100644
index 0000000..f00efc8
--- /dev/null
+++ b/ControlServer/Popup.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Text;
+using System.Windows.Forms;
+
+namespace ControlServer
+{
+ public partial class Popup : Form
+ {
+ public Popup(string message)
+ {
+ InitializeComponent();
+
+ lblText.Text = message;
+ }
+
+ private void btnOk_MouseClick(object sender, MouseEventArgs e)
+ {
+ this.DialogResult = DialogResult.OK; // Form2에 이벤트 전달
+ this.Close();
+ }
+ }
+}
diff --git a/ControlServer/Popup.resx b/ControlServer/Popup.resx
new file mode 100644
index 0000000..8b2ff64
--- /dev/null
+++ b/ControlServer/Popup.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/ControlServer/Program.cs b/ControlServer/Program.cs
new file mode 100644
index 0000000..2ac4501
--- /dev/null
+++ b/ControlServer/Program.cs
@@ -0,0 +1,17 @@
+namespace ControlServer
+{
+ internal static class Program
+ {
+ ///
+ /// The main entry point for the application.
+ ///
+ [STAThread]
+ static void Main()
+ {
+ // To customize application configuration such as set high DPI settings or default font,
+ // see https://aka.ms/applicationconfiguration.
+ ApplicationConfiguration.Initialize();
+ Application.Run(new Form1());
+ }
+ }
+}
\ No newline at end of file
diff --git a/ControlServer/Properties/Resources.Designer.cs b/ControlServer/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..a98024f
--- /dev/null
+++ b/ControlServer/Properties/Resources.Designer.cs
@@ -0,0 +1,73 @@
+//------------------------------------------------------------------------------
+//
+// 이 코드는 도구를 사용하여 생성되었습니다.
+// 런타임 버전:4.0.30319.42000
+//
+// 파일 내용을 변경하면 잘못된 동작이 발생할 수 있으며, 코드를 다시 생성하면
+// 이러한 변경 내용이 손실됩니다.
+//
+//------------------------------------------------------------------------------
+
+namespace ControlServer.Properties {
+ using System;
+
+
+ ///
+ /// 지역화된 문자열 등을 찾기 위한 강력한 형식의 리소스 클래스입니다.
+ ///
+ // 이 클래스는 ResGen 또는 Visual Studio와 같은 도구를 통해 StronglyTypedResourceBuilder
+ // 클래스에서 자동으로 생성되었습니다.
+ // 멤버를 추가하거나 제거하려면 .ResX 파일을 편집한 다음 /str 옵션을 사용하여 ResGen을
+ // 다시 실행하거나 VS 프로젝트를 다시 빌드하십시오.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "18.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// 이 클래스에서 사용하는 캐시된 ResourceManager 인스턴스를 반환합니다.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ControlServer.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// 이 강력한 형식의 리소스 클래스를 사용하여 모든 리소스 조회에 대해 현재 스레드의 CurrentUICulture 속성을
+ /// 재정의합니다.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// System.Drawing.Bitmap 형식의 지역화된 리소스를 찾습니다.
+ ///
+ internal static System.Drawing.Bitmap button_search {
+ get {
+ object obj = ResourceManager.GetObject("button-search", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+ }
+}
diff --git a/ControlServer/Properties/Resources.resx b/ControlServer/Properties/Resources.resx
new file mode 100644
index 0000000..dab1ac7
--- /dev/null
+++ b/ControlServer/Properties/Resources.resx
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+
+ ..\Resources\button-search.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
\ No newline at end of file
diff --git a/ControlServer/Resources/button-search.png b/ControlServer/Resources/button-search.png
new file mode 100644
index 0000000..5cca2a3
Binary files /dev/null and b/ControlServer/Resources/button-search.png differ
diff --git a/ControlServer/TerminalInfo.cs b/ControlServer/TerminalInfo.cs
new file mode 100644
index 0000000..8964f2c
--- /dev/null
+++ b/ControlServer/TerminalInfo.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ControlServer
+{
+ public class TerminalInfo
+ {
+ public string TerminalName { get; set; } = "";
+
+ public string IP { get; set; } = "";
+
+ public string Port { get; set; } = "";
+
+ public string Mac { get; set; } = "";
+
+ public string Path { get; set; } = "";
+
+ public string ProcessName { get; set; } = "";
+ }
+}