Socket 비동기 채팅 프로그램 with Console
Async Socket Chat
Socket 비동기 채팅 프로그램 with Console
구성 요약
- SocketAsyncEventArgs 없이 간단한
async/await
패턴 사용 - 서버: 다중 클라이언트 수용, 메시지 브로드캐스트
- 클라이언트: 메시지 입력, 서버로 전송 + 서버 메시지 수신
- 모두
UTF-8
인코딩 사용
비동기 채팅 서버 (Socket + async)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// AsyncSocketChatServer.cs
using System.Net;
using System.Net.Sockets;
using System.Text;
class AsyncSocketChatServer
{
static List<Socket> clients = new();
static object locker = new();
static async Task Main()
{
var serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverSocket.Bind(new IPEndPoint(IPAddress.Any, 9000));
serverSocket.Listen(100);
Console.WriteLine("서버 시작됨.");
while (true)
{
Socket clientSocket = await serverSocket.AcceptAsync();
Console.WriteLine($"클라이언트 연결됨: {clientSocket.RemoteEndPoint}");
lock (locker) clients.Add(clientSocket);
_ = Task.Run(() => HandleClientAsync(clientSocket));
}
}
static async Task HandleClientAsync(Socket client)
{
byte[] buffer = new byte[1024];
try
{
while (true)
{
int received = await client.ReceiveAsync(buffer, SocketFlags.None);
if (received == 0) break;
string msg = Encoding.UTF8.GetString(buffer, 0, received);
Console.WriteLine($"수신: {msg}");
await BroadcastAsync(client, msg);
}
}
catch (SocketException ex)
{
Console.WriteLine($"소켓 예외: {ex.Message}");
}
finally
{
Console.WriteLine($"클라이언트 연결 종료: {client.RemoteEndPoint}");
lock (locker) clients.Remove(client);
client.Close();
}
}
static async Task BroadcastAsync(Socket sender, string message)
{
byte[] data = Encoding.UTF8.GetBytes(message);
List<Task> tasks = new();
lock (locker)
{
foreach (var client in clients)
{
if (client != sender)
tasks.Add(client.SendAsync(data, SocketFlags.None));
}
}
await Task.WhenAll(tasks);
}
}
비동기 채팅 클라이언트 (Socket + async)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// AsyncSocketChatClient.cs
using System.Net.Sockets;
using System.Text;
class AsyncSocketChatClient
{
static async Task Main()
{
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
await socket.ConnectAsync("127.0.0.1", 9000);
Console.WriteLine("서버에 연결됨.");
_ = Task.Run(async () =>
{
byte[] buffer = new byte[1024];
while (true)
{
int received = await socket.ReceiveAsync(buffer, SocketFlags.None);
if (received == 0) break;
string msg = Encoding.UTF8.GetString(buffer, 0, received);
Console.WriteLine(msg);
}
});
while (true)
{
string? input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input)) continue;
byte[] data = Encoding.UTF8.GetBytes(input);
await socket.SendAsync(data, SocketFlags.None);
}
}
}
장점 요약
Socket
클래스 그대로 사용하면서도async/await
기반이라 UI 스레드랑도 잘 맞음AcceptAsync
,ReceiveAsync
,SendAsync
로 확장성 확보SocketAsyncEventArgs
보다 간단해서 유지보수 편함
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.