asp.net
[.net framework] Socket 통신(서버)
TTTGGG
2025. 2. 18. 13:34
728x90
반응형
SMALL
.net framework 4.7.2 WinForm
여러 클라이언트로부터 지속적으로 데이터를 받아올 수 있도록 구성
클라이언트 목록 관리
실시간 데이터 수신 및 UI 갱신
개별 클라이언트 연결 해제 및 전체 해제 기능
서버 시작 및 종료 기능
using System;
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace SocketServer
{
public partial class Form1 : Form
{
private TcpListener server;
private ConcurrentDictionary<string, TcpClient> clients = new ConcurrentDictionary<string, TcpClient>();
private ConcurrentDictionary<string, CancellationTokenSource> clientTokens = new ConcurrentDictionary<string, CancellationTokenSource>();
private SynchronizationContext syncContext;
public Form1()
{
InitializeComponent();
syncContext = SynchronizationContext.Current;
}
// 서버 시작 버튼
private async void btnStartServer_Click(object sender, EventArgs e)
{
int port = 5000;
server = new TcpListener(IPAddress.Any, port);
server.Start();
AppendLog($"서버 시작: 포트 {port}");
btnStartServer.Enabled = false;
btnStopServer.Enabled = true;
await AcceptClientsAsync();
}
// 클라이언트 연결 대기 (비동기)
private async Task AcceptClientsAsync()
{
while (true)
{
try
{
TcpClient client = await server.AcceptTcpClientAsync();
string clientKey = client.Client.RemoteEndPoint.ToString();
//if (clients.Count >= 130)
//{
// AppendLog($"연결 거부: {clientKey} (최대 클라이언트 초과)");
// client.Close();
// continue;
//}
clients.TryAdd(clientKey, client);
var cts = new CancellationTokenSource();
clientTokens.TryAdd(clientKey, cts);
syncContext.Post(_ =>
{
lstClients.Items.Add(clientKey);
AppendLog($"클라이언트 연결: {clientKey}");
}, null);
_ = HandleClientAsync(client, clientKey, cts.Token);
}
catch (Exception ex)
{
AppendLog($"[에러] 클라이언트 연결 실패: {ex.Message}");
break;
}
}
}
// 클라이언트 데이터 처리 (비동기)
private async Task HandleClientAsync(TcpClient client, string clientKey, CancellationToken token)
{
try
{
using (NetworkStream stream = client.GetStream())
{
byte[] buffer = new byte[1024];
while (!token.IsCancellationRequested)
{
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, token);
if (bytesRead == 0) break;
string receivedData = Encoding.UTF8.GetString(buffer, 0, bytesRead);
syncContext.Post(_ => AppendLog($"[{clientKey}] {receivedData}"), null);
}
}
}
catch (OperationCanceledException)
{
AppendLog($"연결 종료: {clientKey} (사용자 요청)");
}
catch (Exception ex)
{
AppendLog($"[에러] {clientKey}: {ex.Message}");
}
finally
{
DisconnectClient(clientKey);
}
}
// 개별 클라이언트 연결 해제
private void DisconnectClient(string clientKey)
{
if (clients.TryRemove(clientKey, out TcpClient client))
{
client.Close();
}
if (clientTokens.TryRemove(clientKey, out CancellationTokenSource cts))
{
cts.Cancel();
cts.Dispose();
}
syncContext.Post(_ =>
{
lstClients.Items.Remove(clientKey);
AppendLog($"클라이언트 종료: {clientKey}");
}, null);
}
// 선택한 클라이언트 해제 버튼
private void btnDisconnectSelected_Click(object sender, EventArgs e)
{
if (lstClients.SelectedItem is string selectedKey)
{
DisconnectClient(selectedKey);
}
}
// 모든 클라이언트 연결 해제
private void btnDisconnectAll_Click(object sender, EventArgs e)
{
foreach (var key in clients.Keys)
{
DisconnectClient(key);
}
AppendLog("모든 클라이언트 연결 해제");
}
// 서버 정지 버튼
private void btnStopServer_Click(object sender, EventArgs e)
{
foreach (var key in clients.Keys)
{
DisconnectClient(key);
}
server.Stop();
btnStartServer.Enabled = true;
btnStopServer.Enabled = false;
AppendLog("서버 정지됨");
}
// 로그 출력
private void AppendLog(string message)
{
if (txtLog.InvokeRequired)
{
txtLog.Invoke(new Action(() =>
txtLog.AppendText($"{DateTime.Now:HH:mm:ss} {message}{Environment.NewLine}")
));
}
else
{
txtLog.AppendText($"{DateTime.Now:HH:mm:ss} {message}{Environment.NewLine}");
}
}
}
}
![]() |
![]() |
728x90
반응형
LIST