프로젝트 파일 링크
https://github.com/kdoy99/LMS5_Project_08.git
GitHub - kdoy99/LMS5_Project_08
Contribute to kdoy99/LMS5_Project_08 development by creating an account on GitHub.
github.com
서버
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Security.AccessControl;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using LiveCharts;
using LiveCharts.Wpf;
using Newtonsoft.Json;
using SQLite;
namespace Server
{
/// <summary>
/// MainWindow.xaml에 대한 상호 작용 논리
/// </summary>
public partial class MainWindow : Window
{
Socket ServerSocket;
Socket ClientSocket;
// 메모리 차트용
public SeriesCollection PieData { get; set; } // 바인딩 데이터 1 (파이 차트)
public SeriesCollection memorySeries { get; set; } // 바인딩 데이터 2 (라인 차트)
public ChartValues<double> memoryUsage { get; set; } // 라인 차트 바인딩 데이터 용 차트 밸류
// CPU 차트용
public SeriesCollection PieCPU { get; set; } // 바인딩 데이터 1 (파이 차트)
public SeriesCollection cpuSeries { get; set; } // 바인딩 데이터 2 (라인 차트)
public ChartValues<double> cpuUsage { get; set; } // 라인 차트 바인딩 데이터 용 차트 밸류
// HDD 차트용
public SeriesCollection PieHDD { get; set; } // 바인딩 데이터 (파이 차트)
private double cpuFree;
List<Data> dataList;
public MainWindow()
{
InitializeComponent();
// 메모리 변수 초기화
memoryUsage = new ChartValues<double>();
// Binding, 메모리 파이차트
PieData = new SeriesCollection
{
new PieSeries
{
Title = "사용 중",
Values = new ChartValues<double> { 0 },
DataLabels = true,
LabelPoint = chartPoint => $"{chartPoint.Y:F2} GB"
},
new PieSeries
{
Title = "남은 공간",
Values = new ChartValues<double> { 100 },
DataLabels = true,
LabelPoint = chartPoint => $"{chartPoint.Y:F2} GB"
}
};
// Binding, 메모리 라인차트
memorySeries = new SeriesCollection
{
new LineSeries
{
Title = "Memory 사용량 (GB)",
Values = memoryUsage,
PointGeometry = DefaultGeometries.Circle,
PointGeometrySize = 5
}
};
// CPU 변수 초기화
cpuUsage = new ChartValues<double>();
// Binding, CPU 파이차트
PieCPU = new SeriesCollection
{
new PieSeries
{
Title = "사용 중",
Values = new ChartValues<double> { 0 },
DataLabels = true,
LabelPoint = chartPoint => $"{chartPoint.Y:F2}%"
},
new PieSeries
{
Title = "남은 공간",
Values = new ChartValues<double> { 100 },
DataLabels = true,
LabelPoint = chartPoint => $"{chartPoint.Y:F2}%"
}
};
// Binding, CPU 라인차트
cpuSeries = new SeriesCollection
{
new LineSeries
{
Title = "CPU 사용량 (%)",
Values = cpuUsage,
PointGeometry = DefaultGeometries.Circle,
PointGeometrySize = 5
}
};
// Binding, HDD 파이차트
PieHDD = new SeriesCollection
{
new PieSeries
{
Title = "사용 중",
Values = new ChartValues<long>{ 0 },
DataLabels = true,
LabelPoint = chartPoint => $"{chartPoint.Y:F2} GB"
},
new PieSeries
{
Title = "남은 공간",
Values = new ChartValues<long>{ 100 },
DataLabels = true,
LabelPoint = chartPoint => $"{chartPoint.Y:F2} GB"
}
};
DataContext = this;
ReadNoticeDB();
}
private void ReadNoticeDB()
{
using (SQLiteConnection connection = new SQLiteConnection(App.databasePath)) // databasePath : Notice 정보 들어있는 DB
{
connection.CreateTable<Data>();
dataList = connection.Query<Data>("SELECT * FROM Data ORDER BY RANDOM() LIMIT 30");
}
if (dataList != null)
{
HistoryList.ItemsSource = dataList;
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var endPoint = new IPEndPoint(IPAddress.Any, Convert.ToInt32(portBox.Text));
ServerSocket.Bind(endPoint);
ServerSocket.Listen(10);
AcceptClient();
}
private void AcceptClient()
{
var args = new SocketAsyncEventArgs();
args.Completed += ClientAccepted;
ServerSocket.AcceptAsync(args);
AddLog("서비스가 시작되었습니다.");
}
private void ClientAccepted(object sender, SocketAsyncEventArgs e)
{
// 클라이언트와 연결 완료
AddLog("클라이언트와 연결되었습니다.");
// 클라이언트를 상대하기 위해서 동적으로 생성된 소켓을
// 멤버변수에 저장
ClientSocket = e.AcceptSocket;
ReceiveInfo();
}
private void ReceiveInfo()
{
var args = new SocketAsyncEventArgs();
args.SetBuffer(new byte[1024], 0, 1024);
args.Completed += DataReceived;
ClientSocket.ReceiveAsync(args);
}
private void DataReceived(object sender, SocketAsyncEventArgs e)
{
//1. 도착한 바이트 배열을 Json 문자열로 변환
string json = Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred);
//2. Json 문자열을 객체로 역직렬화
try
{
var deviceinfo = JsonConvert.DeserializeObject<Data>(json);
AddLog(json);
//3. 객체의 내용을 UI에 반영
RefreshDeviceInfo(deviceinfo);
}
catch { }
//4. 다시 수신 작업 수행
ReceiveInfo();
}
private void RefreshDeviceInfo(Data data)
{
// 여기에 차트값들 집어넣기
Action action = () =>
{
double percent = (data.RemainMemory / data.TotalMemory) * 100;
TotalMemory.Text = "총 메모리 (GB) : " + data.TotalMemory.ToString("F2");
FreeMemory.Text = "사용 가능한 메모리 (GB) : " + data.FreeMemory.ToString("F2");
RemainMemory.Text = "사용 중인 메모리 (GB) : " + data.RemainMemory.ToString("F2");
MemoryTitle.Text = "메모리 사용량 (%) : " + percent.ToString("F2");
MemoryBar.Value = percent;
// memory 파이 차트 업데이트
PieData[0].Values[0] = data.RemainMemory;
PieData[1].Values[0] = data.FreeMemory;
// memory 라인 차트 업데이트
memoryUsage.Add(Math.Round(data.RemainMemory, 2));
if (memoryUsage.Count > 60)
memoryUsage.RemoveAt(0);
// CPU 용 데이터 변수 지정
cpuFree = 100 - data.cpuValueData;
// CPU 파이 차트 업데이트
PieCPU[0].Values[0] = Math.Round(data.cpuValueData, 2);
PieCPU[1].Values[0] = Math.Round(cpuFree, 2);
// CPU 라인 차트 업데이트
cpuUsage.Add(Math.Round(data.cpuValueData, 2));
// 데이터 포인트 수 제한
if (cpuUsage.Count > 60)
cpuUsage.RemoveAt(0);
// HDD 파이 차트 업데이트
PieHDD[0].Values[0] = data.useSize;
PieHDD[1].Values[0] = data.freeSize;
HDD_Name.Text = $"HDD 사용량 ({data.HDDname})";
// 지정된 경로에 생성할 DB 연결 객체 생성
using (SQLiteConnection connection = new SQLiteConnection(App.databasePath))
{
// Data 클래스 정의를 기반으로 SQLite DB Table 생성 (테이블이 없을 경우, 있으면 X)
connection.CreateTable<Data>();
// UI 컨트롤에 입력된 데이터를 data 객체 형태로, 생성한 SQLite DB Table에 삽입
connection.Insert(data);
}
};
Dispatcher.Invoke(action);
}
private void AddLog(string log)
{
//메인 스레드에서 UI 속성을 접근하는 로직이 수행되도록 위임
Action action = () => { txtLog.AppendText(log + "\r\n"); };
Dispatcher.Invoke(action);
}
}
}
서버 XAML
<Window x:Class="Server.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Server"
xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
mc:Ignorable="d"
Title="MainWindow" Height="600" Width="900">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="10*"/>
<RowDefinition Height="10*"/>
<RowDefinition Height="5*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid>
<TextBlock TextWrapping="Wrap" Text="Memory 사용량" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="20" FontWeight="Bold"/>
</Grid>
<Grid Grid.Column="1">
<TextBlock TextWrapping="Wrap" Text="CPU 사용량" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="20" FontWeight="Bold"/>
</Grid>
<Grid Grid.Column="2" Grid.ColumnSpan="2">
<TextBlock x:Name="HDD_Name" TextWrapping="Wrap" Text="HDD 사용량" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="20" FontWeight="Bold"/>
</Grid>
<Grid Grid.Row="1" Grid.Column="0">
<lvc:PieChart x:Name="MemoryChart" Margin="20,20,20,20" Series="{Binding PieData}">
<lvc:PieChart.LegendLocation>
Right
</lvc:PieChart.LegendLocation>
</lvc:PieChart>
</Grid>
<Grid Grid.Row="1" Grid.Column="1">
<lvc:PieChart x:Name="CPUChart" Margin="20,20,20,20" Series="{Binding PieCPU}">
<lvc:PieChart.LegendLocation>
Right
</lvc:PieChart.LegendLocation>
</lvc:PieChart>
</Grid>
<Grid Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="2">
<lvc:PieChart x:Name="HDDChart" Margin="20,20,20,20" Series="{Binding PieHDD}">
<lvc:PieChart.LegendLocation>
Right
</lvc:PieChart.LegendLocation>
</lvc:PieChart>
</Grid>
<Grid Grid.Row="2">
<lvc:CartesianChart Series="{Binding memorySeries}" Margin="20,20,20,20">
<lvc:CartesianChart.AxisX>
<lvc:Axis Title="시간(초)" />
</lvc:CartesianChart.AxisX>
<lvc:CartesianChart.AxisY>
<lvc:Axis Title="Memory 사용량 (GB)" MinValue="0" MaxValue="16" />
</lvc:CartesianChart.AxisY>
</lvc:CartesianChart>
</Grid>
<Grid Grid.Row="2" Grid.Column="1">
<lvc:CartesianChart Series="{Binding cpuSeries}" Margin="20,20,20,20">
<lvc:CartesianChart.AxisX>
<lvc:Axis Title="시간(초)" />
</lvc:CartesianChart.AxisX>
<lvc:CartesianChart.AxisY>
<lvc:Axis Title="CPU 사용량 (%)" MinValue="0" MaxValue="100" />
</lvc:CartesianChart.AxisY>
</lvc:CartesianChart>
</Grid>
<Grid Grid.Row="2" Grid.Column="2" Grid.ColumnSpan="2">
<ListView x:Name="HistoryList" d:ItemsSource="{d:SampleData ItemCount=30}" Margin="10,40,10,10">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock FontSize="10" FontWeight="Bold">
<Run Text="{Binding LogNumber}" />
<Run Text="번째 데이터" />
</TextBlock>
<TextBlock FontSize="8" FontWeight="Bold" Foreground="Blue">
<Run Text="총 메모리 (GB) : " />
<Run Text="{Binding TotalMemory}" />
</TextBlock>
<TextBlock FontSize="8" FontWeight="Bold" Foreground="Blue">
<Run Text="남은 메모리 (GB) : " />
<Run Text="{Binding FreeMemory}" />
</TextBlock>
<TextBlock FontSize="8" FontWeight="Bold" Foreground="Blue">
<Run Text="사용중인 메모리 (GB) : " />
<Run Text="{Binding RemainMemory}" />
</TextBlock>
<TextBlock FontSize="8" FontWeight="Bold" Foreground="Blue">
<Run Text="CPU 사용량 (%) : " />
<Run Text="{Binding cpuValueData}" />
</TextBlock>
<TextBlock FontSize="8" FontWeight="Bold" Foreground="Blue">
<Run Text="HDD 이름 : " />
<Run Text="{Binding HDDname}" />
</TextBlock>
<TextBlock FontSize="8" FontWeight="Bold" Foreground="Blue">
<Run Text="HDD 용량 : " />
<Run Text="{Binding totalSize}" />
</TextBlock>
<TextBlock FontSize="8" FontWeight="Bold" Foreground="Blue">
<Run Text="HDD 남은 용량 : " />
<Run Text="{Binding freeSize}" />
</TextBlock>
<TextBlock FontSize="8" FontWeight="Bold" Foreground="Blue">
<Run Text="HDD 사용중인 용량 : " />
<Run Text="{Binding useSize}" />
</TextBlock>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<TextBlock Margin="0,10,0,0" TextWrapping="Wrap" Text="이전 데이터 로그" VerticalAlignment="Top" HorizontalAlignment="Center" FontWeight="Bold" FontSize="20"/>
</Grid>
<Grid Grid.Row="3" Grid.Column="0">
<TextBox x:Name="TotalMemory" TextWrapping="Wrap" Text="총 메모리 (GB) : " VerticalAlignment="Top" IsReadOnly="True" Margin="10,0,10,0"/>
<TextBox x:Name="FreeMemory" TextWrapping="Wrap" Text="사용 가능한 메모리 (GB) : " VerticalAlignment="Top" IsReadOnly="True" Margin="10,20,10,0"/>
<TextBox x:Name="RemainMemory" TextWrapping="Wrap" Text="사용 중인 메모리 (GB) : " VerticalAlignment="Top" IsReadOnly="True" Margin="10,40,10,0"/>
<TextBox x:Name="MemoryTitle" TextWrapping="Wrap" Text="메모리 사용량 (%) : " VerticalAlignment="Top" IsReadOnly="True" Margin="10,60,10,0"/>
<ProgressBar x:Name="MemoryBar" Margin="10,80,10,5"/>
</Grid>
<Grid Grid.Row="3" Grid.Column="3">
<Button Content="서버 구동" Margin="10,0,10,40" Click="Button_Click" FontSize="24" FontWeight="Bold" />
<TextBox x:Name="portBox" TextWrapping="Wrap" Text="10004" VerticalAlignment="Bottom" Margin="50,0,10,10"/>
<Label Content="Port" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="10,0,0,5"/>
</Grid>
<Grid Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2">
<TextBox x:Name="txtLog" TextWrapping="Wrap" Margin="10,0,10,5" />
</Grid>
</Grid>
</Window>
클라이언트
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Diagnostics;
using System.Threading;
using System.Management;
using LiveCharts;
using LiveCharts.Wpf;
using System.Collections.ObjectModel;
using System.Net.Sockets;
using System.Windows.Threading;
using System.Text.Json.Serialization;
using Newtonsoft.Json;
using System.Net;
using System.Timers;
using System.IO;
namespace Client
{
public partial class MainWindow : Window
{
// 클라이언트 소켓
Socket ClientSocket;
// 타이머 변수 만들기
public DispatcherTimer timer = new DispatcherTimer();
// 데이터 변수
// 메모리
private double total_memory;
private double free_memory;
private double remain_memory;
// CPU
private double cpuValue;
// HDD
private string HDDName;
private long TotalSize;
private long FreeSize;
private long UseSize;
// 메모리 차트용
public SeriesCollection PieData { get; set; } // 바인딩 데이터 1 (파이 차트)
public SeriesCollection memorySeries { get; set; } // 바인딩 데이터 2 (라인 차트)
public ChartValues<double> memoryUsage { get; set; } // 라인 차트 바인딩 데이터 용 차트 밸류
// CPU 차트용
public SeriesCollection PieCPU { get; set; } // 바인딩 데이터 1 (파이 차트)
public SeriesCollection cpuSeries { get; set; } // 바인딩 데이터 2 (라인 차트)
public ChartValues<double> cpuUsage { get; set; } // 라인 차트 바인딩 데이터 용 차트 밸류
private PerformanceCounter cpuCounter; // CPU 파이 차트용
// HDD 차트용
public SeriesCollection PieHDD { get; set; } // 바인딩 데이터 (파이 차트)
public MainWindow()
{
InitializeComponent();
// Memory 변수 초기화
memoryUsage = new ChartValues<double>();
// Binding, 메모리 파이차트
PieData = new SeriesCollection
{
new PieSeries
{
Title = "사용 중",
Values = new ChartValues<double> { 0 },
DataLabels = true,
LabelPoint = chartPoint => $"{chartPoint.Y:F2} GB"
},
new PieSeries
{
Title = "남은 공간",
Values = new ChartValues<double> { 100 },
DataLabels = true,
LabelPoint = chartPoint => $"{chartPoint.Y:F2} GB"
}
};
// Binding, 메모리 라인차트
memorySeries = new SeriesCollection
{
new LineSeries
{
Title = "Memory 사용량 (GB)",
Values = memoryUsage,
PointGeometry = DefaultGeometries.Circle,
PointGeometrySize = 5
}
};
// CPU 변수 초기화
cpuUsage = new ChartValues<double>();
// Binding, CPU 파이차트
PieCPU = new SeriesCollection
{
new PieSeries
{
Title = "사용 중",
Values = new ChartValues<double> { 0 },
DataLabels = true,
LabelPoint = chartPoint => $"{chartPoint.Y:F2}%"
},
new PieSeries
{
Title = "남은 공간",
Values = new ChartValues<double> { 100 },
DataLabels = true,
LabelPoint = chartPoint => $"{chartPoint.Y:F2}%"
}
};
// Binding, CPU 라인차트
cpuSeries = new SeriesCollection
{
new LineSeries
{
Title = "CPU 사용량 (%)",
Values = cpuUsage,
PointGeometry = DefaultGeometries.Circle,
PointGeometrySize = 5
}
};
// 퍼포먼스 카운터 초기화 및 미리 호출
cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
cpuCounter.NextValue();
// Binding, HDD 파이차트
PieHDD = new SeriesCollection
{
new PieSeries
{
Title = "사용 중",
Values = new ChartValues<long>{ 0 },
DataLabels = true,
LabelPoint = chartPoint => $"{chartPoint.Y:F2} GB"
},
new PieSeries
{
Title = "남은 공간",
Values = new ChartValues<long>{ 100 },
DataLabels = true,
LabelPoint = chartPoint => $"{chartPoint.Y:F2} GB"
}
};
DataContext = this;
}
private void memoryUpdate()
{
// 컴퓨터 메모리 데이터 불러오고 텍스트 박스에 저장함
ManagementClass cls = new ManagementClass("Win32_OperatingSystem");
ManagementObjectCollection instances = cls.GetInstances();
foreach (ManagementObject info in instances)
{
total_memory = double.Parse(info["TotalVisibleMemorySize"].ToString()) / (1024 * 1024);
free_memory = double.Parse(info["FreePhysicalMemory"].ToString()) / (1024 * 1024);
remain_memory = total_memory - free_memory;
}
// HDD 정보
DriveInfo[] hddDrives = DriveInfo.GetDrives();
foreach (DriveInfo drive in hddDrives)
{
if (drive.DriveType == DriveType.Fixed)
{
HDDName = drive.Name.ToString();
TotalSize = drive.TotalSize / 1024 / 1024 / 1024;
FreeSize = drive.AvailableFreeSpace / 1024 / 1024 / 1024;
UseSize = (drive.TotalSize - drive.AvailableFreeSpace) / 1024 / 1024 / 1024;
}
}
// memory 파이 차트 업데이트
PieData[0].Values[0] = remain_memory;
PieData[1].Values[0] = free_memory;
// memory 라인 차트 업데이트
memoryUsage.Add(Math.Round(remain_memory, 2));
if (memoryUsage.Count > 60)
memoryUsage.RemoveAt(0);
// CPU 용 데이터 변수 지정
cpuValue = cpuCounter.NextValue();
double cpuFree = 100 - cpuValue;
// CPU 파이 차트 업데이트
PieCPU[0].Values[0] = Math.Round(cpuValue, 2);
PieCPU[1].Values[0] = Math.Round(cpuFree, 2);
// CPU 라인 차트 업데이트
cpuUsage.Add(Math.Round(cpuValue, 2));
// 데이터 포인트 수 제한
if (cpuUsage.Count > 60)
cpuUsage.RemoveAt(0);
// HDD 파이 차트 업데이트
PieHDD[0].Values[0] = UseSize;
PieHDD[1].Values[0] = FreeSize;
HDD_Name.Text = $"HDD 사용량 ({HDDName})";
}
private void ConnectButton_Click(object sender, RoutedEventArgs e)
{
int port = Convert.ToInt32(PortBox.Text); // PortBox 안에 있는 값을 port 변수에 저장
ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var endPoint = new IPEndPoint(IPAddress.Parse(IPBox.Text), port); // IP와 Port 값 따와서 사용
var args = new SocketAsyncEventArgs();
args.RemoteEndPoint = endPoint;
args.Completed += ServerConnected;
ClientSocket.ConnectAsync(args);
}
private void ServerConnected(object sender, SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
// 서버 연결 성공시 서버로부터 제어 요청 받기
ReceiveControl();
}
}
private void ReceiveControl()
{
var args = new SocketAsyncEventArgs();
args.SetBuffer(new byte[1024], 0, 1024);
args.Completed += ControlReceived;
ClientSocket.ReceiveAsync(args);
}
private void ControlReceived(object sender, SocketAsyncEventArgs e)
{
string json = Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred);
var control = JsonConvert.DeserializeObject<ClientData>(json);
}
private void timer_Tick(object sender, EventArgs e)
{
// 타이머 1번 발생 = timer_Tick
memoryUpdate();
SendDeviceInfo();
}
private void SendDeviceInfo()
{
// 소켓 O, 서버 연결 O 확인
if (ClientSocket == null || !ClientSocket.Connected)
return;
try
{
// 1. 전송할 데이터 엔터티 객체에 준비
var info = new ClientData
{
// 메모리
TotalMemory = Math.Round(total_memory, 2),
FreeMemory = Math.Round(free_memory, 2),
RemainMemory = Math.Round(remain_memory, 2),
// CPU
cpuValueData = Math.Round(cpuValue, 2),
// HDD
HDDname = HDDName,
totalSize = TotalSize,
freeSize = FreeSize,
useSize = UseSize
};
// 2. 객체를 json 문자열로 직렬화
string json = JsonConvert.SerializeObject(info);
// 3. 문자열 byte 배열로 변환
byte[] bytesToSend = Encoding.UTF8.GetBytes(json);
// 4. SocketAsyncEventArgs 객체에 전송할 데이터 설정
var args = new SocketAsyncEventArgs();
args.SetBuffer(bytesToSend, 0, bytesToSend.Length);
// 5. 비동기적으로 전송
ClientSocket.SendAsync(args);
}
catch { }
}
// 클라이언트 창 로드될 때 발생되는 이벤트
private void ClientWindow_Loaded(object sender, RoutedEventArgs e)
{
// 타이머 설정
timer.Interval = TimeSpan.FromMilliseconds(1000); // 1초
timer.Tick += new EventHandler(timer_Tick);
timer.Start();
}
}
}
클라이언트 XAML
<Window x:Name="ClientWindow" x:Class="Client.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Project08"
xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
mc:Ignorable="d"
Title="MainWindow" Height="600" Width="900" Loaded="ClientWindow_Loaded">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="14*"/>
<RowDefinition Height="14*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid>
<TextBlock TextWrapping="Wrap" Text="Memory 사용량" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="20" FontWeight="Bold"/>
</Grid>
<Grid Grid.Column="1">
<TextBlock TextWrapping="Wrap" Text="CPU 사용량" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="20" FontWeight="Bold"/>
</Grid>
<Grid Grid.Column="2">
<TextBlock x:Name="HDD_Name" TextWrapping="Wrap" Text="HDD 사용량" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="20" FontWeight="Bold"/>
</Grid>
<Grid Grid.Row="1">
<lvc:PieChart x:Name="DataChart" Margin="20,20,20,20" Series="{Binding PieData}">
<lvc:PieChart.LegendLocation>
Right
</lvc:PieChart.LegendLocation>
</lvc:PieChart>
</Grid>
<Grid Grid.Row="1" Grid.Column="1">
<lvc:PieChart x:Name="CPUChart" Margin="20,20,20,20" Series="{Binding PieCPU}">
<lvc:PieChart.LegendLocation>
Right
</lvc:PieChart.LegendLocation>
</lvc:PieChart>
</Grid>
<Grid Grid.Row="1" Grid.Column="2">
<lvc:PieChart x:Name="HDDChart" Margin="20,20,20,20" Series="{Binding PieHDD}">
<lvc:PieChart.LegendLocation>
Right
</lvc:PieChart.LegendLocation>
</lvc:PieChart>
</Grid>
<Grid Grid.Row="2">
<lvc:CartesianChart Series="{Binding memorySeries}" Margin="20,20,20,20">
<lvc:CartesianChart.AxisX>
<lvc:Axis Title="시간(초)" />
</lvc:CartesianChart.AxisX>
<lvc:CartesianChart.AxisY>
<lvc:Axis Title="Memory 사용량 (GB)" MinValue="0" MaxValue="16" />
</lvc:CartesianChart.AxisY>
</lvc:CartesianChart>
</Grid>
<Grid Grid.Column="1" Grid.Row="2">
<lvc:CartesianChart Series="{Binding cpuSeries}" Margin="20,20,20,20">
<lvc:CartesianChart.AxisX>
<lvc:Axis Title="시간(초)" />
</lvc:CartesianChart.AxisX>
<lvc:CartesianChart.AxisY>
<lvc:Axis Title="CPU 사용량 (%)" MinValue="0" MaxValue="100" />
</lvc:CartesianChart.AxisY>
</lvc:CartesianChart>
</Grid>
<Grid Grid.Column="2" Grid.Row="2">
<Button x:Name="ConnectButton" Content="서버 연결" HorizontalAlignment="Right" VerticalAlignment="Bottom" Click="ConnectButton_Click" Margin="0,0,10,10" FontSize="24" FontWeight="Bold" Height="47" Width="131"/>
<TextBox x:Name="IPBox" TextWrapping="Wrap" Text="127.0.0.1" HorizontalAlignment="Right" VerticalAlignment="Bottom" Width="95" Margin="0,0,158,39"/>
<Label Content="IP" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0,0,263,37"/>
<TextBox x:Name="PortBox" HorizontalAlignment="Right" TextWrapping="Wrap" Text="10004" VerticalAlignment="Bottom" Width="95" Margin="0,0,158,9"/>
<Label Content="Port" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0,0,258,7"/>
</Grid>
</Grid>
</Window>
그 외 파일은 Git에서 확인 가능
사용한 패키지
서버 : LiveCharts, LiveCharts.Wpf, Newtonsoft.Json, sqlite-net-pcl
클라이언트 : LiveCharts, LiveCharts.Wpf, Newtonsoft.Json, sqlite-net-pcl, System.Management
'C#' 카테고리의 다른 글
LMS5_Project09 C# WPF 프로젝트 - 서버/클라이언트 채팅 프로그램 (0) | 2025.03.06 |
---|---|
C# WPF 데이터베이스 연결 (0) | 2025.02.05 |
C# 문제풀이 2 (0) | 2025.01.24 |
C# 문제풀이 1 (3) | 2025.01.24 |
C# 클래스 과제 마무리 (0) | 2025.01.24 |