초기 커밋.

This commit is contained in:
chainsecure
2026-05-28 14:48:48 +09:00
parent 377498fae8
commit 5d6ee943f6
31 changed files with 3182 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net10.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
<PackageReference Include="RestSharp" Version="114.0.0" />
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project>

316
ControlServer/Form1.Designer.cs generated Normal file
View File

@@ -0,0 +1,316 @@
namespace ControlServer
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
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;
}
}

503
ControlServer/Form1.cs Normal file
View File

@@ -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<TerminalInfo> terminalList = new List<TerminalInfo>(); // 리스트 생성
private Dictionary<string, TcpClient> _connectedAgents = new Dictionary<string, TcpClient>();
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) { }
}
}

141
ControlServer/Form1.resx Normal file
View File

@@ -0,0 +1,141 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="Col0.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="Col1.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="Col2.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="Col3.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="Col4.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="Col5.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="Col8.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
</root>

151
ControlServer/Form2.Designer.cs generated Normal file
View File

@@ -0,0 +1,151 @@
namespace ControlServer
{
partial class Form2
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
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;
}
}

65
ControlServer/Form2.cs Normal file
View File

@@ -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();
}
}
}

120
ControlServer/Form2.resx Normal file
View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

317
ControlServer/Form3.Designer.cs generated Normal file
View File

@@ -0,0 +1,317 @@
namespace ControlServer
{
partial class Form3
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
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;
}
}

57
ControlServer/Form3.cs Normal file
View File

@@ -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 저장
}
}
}

120
ControlServer/Form3.resx Normal file
View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

166
ControlServer/Form4.Designer.cs generated Normal file
View File

@@ -0,0 +1,166 @@
namespace ControlServer
{
partial class Form4
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
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;
}
}

35
ControlServer/Form4.cs Normal file
View File

@@ -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();
}
}
}

138
ControlServer/Form4.resx Normal file
View File

@@ -0,0 +1,138 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="Col5.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="Col0.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="Col3.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="Col4.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="Col6.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="Col7.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
</root>

82
ControlServer/Popup.Designer.cs generated Normal file
View File

@@ -0,0 +1,82 @@
namespace ControlServer
{
partial class Popup
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
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;
}
}

26
ControlServer/Popup.cs Normal file
View File

@@ -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();
}
}
}

120
ControlServer/Popup.resx Normal file
View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

17
ControlServer/Program.cs Normal file
View File

@@ -0,0 +1,17 @@
namespace ControlServer
{
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[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());
}
}
}

View File

@@ -0,0 +1,73 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 이 코드는 도구를 사용하여 생성되었습니다.
// 런타임 버전:4.0.30319.42000
//
// 파일 내용을 변경하면 잘못된 동작이 발생할 수 있으며, 코드를 다시 생성하면
// 이러한 변경 내용이 손실됩니다.
// </auto-generated>
//------------------------------------------------------------------------------
namespace ControlServer.Properties {
using System;
/// <summary>
/// 지역화된 문자열 등을 찾기 위한 강력한 형식의 리소스 클래스입니다.
/// </summary>
// 이 클래스는 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() {
}
/// <summary>
/// 이 클래스에서 사용하는 캐시된 ResourceManager 인스턴스를 반환합니다.
/// </summary>
[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;
}
}
/// <summary>
/// 이 강력한 형식의 리소스 클래스를 사용하여 모든 리소스 조회에 대해 현재 스레드의 CurrentUICulture 속성을
/// 재정의합니다.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// System.Drawing.Bitmap 형식의 지역화된 리소스를 찾습니다.
/// </summary>
internal static System.Drawing.Bitmap button_search {
get {
object obj = ResourceManager.GetObject("button-search", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
}
}

View File

@@ -0,0 +1,124 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="button-search" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\button-search.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

Binary file not shown.

After

Width:  |  Height:  |  Size: 713 B

View File

@@ -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; } = "";
}
}