C# socket ํ†ต์‹ 

์•ˆ๋…•ํ•˜์„ธ์š” wpf ์ดˆ๋ณด์ž์ž…๋‹ˆ๋‹ค.
์™ธ๊ตญ ์œ ํŠœ๋ธŒ๋ฅผ ๋ณด๋ฉด์„œ socket ํ†ต์‹ ์„ ์ด์šฉํ•œ ์ฑ„ํŒ… ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ค์–ด ๋ดค๋Š”๋ฐ
์ด๊ฒŒ ์˜์–ด๋กœ ์ž…๋ ฅํ•˜๋ฉด์€ ์ถœ๋ ฅ์ด ์ž˜ ๋˜์ง€๋งŒ ์˜์–ด์™ธ์— ๋‹ค๋ฅธ ๊ธ€์ž ํ•œ์ž, ํ•œ๊ธ€๋“ฑ์„ ์ž…๋ ฅํ•  ๋•Œ ํฐํŠธ๊ฐ€ ๊นจ์ง€๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
์˜ค๋ฅ˜

<์ž…๋ ฅ๋œ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ”์ดํŠธํ™”?>
public string ReadMessage()
{
byte[] msgBuffer;
var length = ReadInt32();
msgBuffer = new byte[length];
_ns.Read(msgBuffer, 0, length);
var msg = Encoding.Default.GetString(msgBuffer);
return msg;
}

๊ทธ๋ž˜์„œ ๋ญ”๊ฐ€ ๋ฐ”์ดํŠธ์˜ ๊ธธ์ด๋ฅผ ์ •ํ•˜์ง€ ์•Š์•„์„œ ๊ทธ๋Ÿฐ๊ฐ€ ์‹ถ์–ด์„œ [length]์— 1024๊ฐ’์„ ์ค˜๋ดค๋Š”๋ฐ ๊ฐ‘์ž๊ธฐ ๊นจ์ง ์—†์ด ์ž˜ ๋‚˜์˜ต๋‹ˆ๋‹ค.
1024๊ฐ’์„ ๋ถ€์—ฌํ–ˆ์„ ๋•Œ ์™œ ์ถœ๋ ฅ์ด ๋˜์—ˆ๋Š”์ง€ ์•„์ง๊นŒ์ง€ ์ดํ•ด๋Š” ์•ˆ๋ฉ๋‹ˆ๋‹ค.
๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ ๋œ ์ค„ ์•Œ์•˜์ง€๋งŒ, ์ฝ˜์†”์ฐฝ์—๋Š” ์‚ฌ์šฉ์ž ์ด๋ฆ„๊ณผ ์ฑ„ํŒ…๋“ค์ด ๋ฌธ์ œ ์—†์ด ์ž˜ ๋‚˜์˜ค์ง€๋งŒ ๋ฉ”์ธ ์œˆ๋„์šฐ ์ฐฝ์—์„œ๋Š” ์‚ฌ์šฉ์ž์ด๋ฆ„๋งŒ ๋‚˜์˜ค๊ณ  ๋ณด๋‚ธ ๋ฉ”์‹œ์ง€๊ฐ€ ํ™”๋ฉด์— ๋ณด์ด์งˆ ์•Š์Šต๋‹ˆ๋‹ค.
๋ฌธ์ œ 2

<๋ฐ”์ดํŠธํ™” ๋œ ๋ฉ”์‹œ์ง€๋ฅผ ์ฝ˜์†”, ์œˆ๋„์šฐ ์ฐฝ์— ๋ณด์—ฌ์ง€๋„๋ก ํ•˜๋Š” >
void Process()
{
while (true)
{
try
{
var opcode = _packetReader.ReadByte();
switch (opcode)
{
case 5:
var msg = _packetReader.ReadMessage();
Console.WriteLine($โ€œ[{DateTime.Now}]: ๋ณด๋‚ธ ๋ฉ”์‹œ์ง€ {Username} {msg}โ€);
Program.BroadcastMessage($"[{DateTime.Now}]: ๋ณด๋‚ธ " + $โ€œ๋ฉ”์‹œ์ง€ {Username} {msg}โ€);
break;
default:
break;
}
}

๊ทผ๋ฐ ์›ƒ๊ธด๊ฑด Program.BroadcastMessage($"[{DateTime.Now}]: ๋ณด๋‚ธ " + $โ€œ๋ฉ”์‹œ์ง€ {Username} {msg}โ€);
์—์„œ {username}์„ ์ง€์šฐ๋ฉด ๋ณด๋‚ธ ๋ฉ”์‹œ์ง€๊ฐ€ ์ถœ๋ ฅ์ด ๋œ๋‹ค๋Š” ๊ฒƒ ์ž…๋‹ˆ๋‹ค.

4์ผ๋™์•ˆ ์ด๊ฑธ ํ•ด๊ฒฐ๋ชปํ•˜๊ณ  ๊ณ„์† ์ผ๋‹ค๊ฐ€ ๊ณ ์ณค๋‹ค๊ฐ€ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹คโ€ฆ ๋„์›€ ๋ถ€ํƒ๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.
๋„ค์ด๋ฒ„ MYBOX ์ „์ฒด ์†Œ์Šค ์ฝ”๋“œ zipํŒŒ์ผ๋กœ ์••์ถ•ํ•ด ๋†“์€ ๊ณณ ์ž…๋‹ˆ๋‹ค.

2๊ฐœ์˜ ์ข‹์•„์š”

์†Œ์Šค์—์„œ Encoding.Default.GetBytes๋กœ ๋˜์–ด์žˆ๋Š” ๋ถ€๋ถ„์„
Encoding.UTF8.GetBytes ๋กœ ์ „๋ถ€ ๋ฐ”๊ฟ”์ฃผ์‹œ๋ฉด ๋ ๊ฒ๋‹ˆ๋‹ค. (์„œ๋ฒ„,ํด๋ผ์ด์–ธํŠธ ๋™์ผํ•˜๊ฒŒ)
๋‹ค๋งŒ, ์ฝ์–ด๋“ค์ด๋Š” Byte์ˆ˜๋ฅผ ์ •ํ•˜๋Š” ๋ถ€๋ถ„์—์„œ ๋ฌธ์ œ๊ฐ€ ์žˆ์–ด๋ณด์ž…๋‹ˆ๋‹คโ€ฆ
์ด๊ฒƒ๋งŒ ํ•ด๊ฒฐํ•˜์‹œ๋ฉด ์ž˜ ๋  ๊ฒƒ ๊ฐ™์•„์š”!

1๊ฐœ์˜ ์ข‹์•„์š”

UTF8, Default,ASCII ๋“ฑ๋“ฑ ๋‹ค ๋ฐ”๊ฟ”๋ดค๋Š”๋ฐ ๋™์ผํ•ด์š” ใ… ใ… 
Byte์ˆ˜๋ฅผ ์–ด๋–ป๊ฒŒ ์ •ํ•ด์ฃผ๋ฉด ๋ ๊นŒ์š”?

2๊ฐœ์˜ ์ข‹์•„์š”

๊ทธ๋ž˜์„œ ๋ญ”๊ฐ€ ๋ฐ”์ดํŠธ์˜ ๊ธธ์ด๋ฅผ ์ •ํ•˜์ง€ ์•Š์•„์„œ ๊ทธ๋Ÿฐ๊ฐ€ ์‹ถ์–ด์„œ [length]์— 1024๊ฐ’์„ ์ค˜๋ดค๋Š”๋ฐ ๊ฐ‘์ž๊ธฐ ๊นจ์ง ์—†์ด ์ž˜ ๋‚˜์˜ต๋‹ˆ๋‹ค.

๊ธฐ์กด์— length๊ฐ€ 1์ด์—ˆ๋˜ ๊ฒƒ ๊ฐ™๋„ค์š”โ€ฆ buffer์˜ ๊ธธ์ด๊ฐ€ 1๊ธ€์ž๋งŒ ์ฝ์„ ์ˆ˜ ์žˆ๊ธฐ์— ๊ทธ๋žฌ๋˜ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ ascii๋Š” 1๊ธ€์ž๋ฅผ ํ‘œํ˜„ํ•˜๋Š”๋ฐ 1byte๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
ํ•˜์ง€๋งŒ ํ•œ๊ธ€์€ 1๊ธ€์ž๋ฅผ ํ‘œํ˜„ํ•˜๋Š”๋ฐ 2byte๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์ธ์ฝ”๋”ฉ ๊ด€๋ จ๋œ ๋ฌธ์ œ์ธ ๊ฒƒ ๊ฐ™์€๋ฐ, GUI์ชฝ์€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์–ด์„œ ํ™•์‹คํžˆ ๋‹ต์„ ๋ชป๋“œ๋ฆฌ๊ฒ ๋„ค์š”

2๊ฐœ์˜ ์ข‹์•„์š”

PacketReader์˜ ReadMessage()๋ฅผ

var count = _ns.Read(msgBuffer,0,1024);
var msg = Encoding.Default.GetString(msgBuffer, 0, count);
return msg;

์ด๋Ÿฐ ์‹์œผ๋กœ ๋ฐ”๊ฟ” ์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.

โ€ฆ

๊ทธ๋Ÿฐ๋ฐ Read() ๋ฉ”์†Œ๋“œ๊ฐ€ ์ „์ฒด ํŒจํ‚ท์„ ๋‹ค ์ฝ์ง€ ๋ชปํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ BinaryReader์˜ ReadString()์„ ์ด์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๋ณด๋‚ผ ๋•Œ๋Š” BinaryWriter์˜ Write()๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ด๊ณ ์š”.

3๊ฐœ์˜ ์ข‹์•„์š”

1. ์ฒซ ๋ฒˆ์งธ ๋ฌธ์ œ
PacketBuilder์—์„œ ๋ฉ”์‹œ์ง€๋ฅผ writeํ•  ๋•Œ ๋ฉ”์‹œ์ง€์˜ ๊ธธ์ด๋ฅผ string.Length๋กœ ์นด์šดํŠธํ•˜๋Š” ๊ฒƒ์—์„œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

string message์˜ ๊ธธ์ด์™€ ์ธ์ฝ”๋”ฉ ๋œ byte ๋ฐฐ์—ด์˜ ๊ธธ์ด๊ฐ€ ๋‹ค๋ฅธ๋ฐ, ๊ธธ์ด๋Š” string.Length๋ฅผ ๋ณด๋‚ด๊ณ  ์ •์ž‘ ๋ฉ”์‹œ์ง€๋Š” ์ธ์ฝ”๋”ฉ ๋œ byte ๋ฐฐ์—ด๋กœ ๋ณด๋‚ด๋‹ˆ ์ค‘๊ฐ„์—์„œ ๋ฉ”์‹œ์ง€๊ฐ€ ์งค๋ฆฌ๊ฒŒ ๋˜๋Š” ๊ฑฐ์ฃ . ๋ฐ˜๋ฉด์— ๋ฐ”์ดํŠธ ๋ฐฐ์—ด์˜ ๊ธธ์ด๋ฅผ 1024๋กœ ๊ณ ์ •ํ•ด์คฌ์„ ๋•Œ๋Š” ๊ทธ ๋ฒ”์œ„ ์•ˆ์—์„œ๋Š” ๋ฌธ์ œ๊ฐ€ ์—†๋Š” ๊ฑฐ๊ตฌ์š”.

2. ๋‘ ๋ฒˆ์งธ ๋ฌธ์ œ
์ฒซ ๋ฒˆ์งธ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋ฐ”์ดํŠธ ๋ฐฐ์—ด์˜ ๊ธธ์ด๋ฅผ 1024๋กœ ๊ณ ์ •ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. UserName์„ ๋ฉ”์‹œ์ง€์™€ ๋™์ผํ•œ ํ”„๋กœํ† ์ฝœ๋กœ ๋ณด๋‚ด๋Š”๋ฐ ๋ฐ”์ดํŠธ ๋ฐฐ์—ด์ด 1024๋กœ ๊ณ ์ •๋˜์–ด ์žˆ์œผ๋‹ˆ ์ŠคํŠธ๋ฆผ์—์„œ UserName์„ ์ฝ๋Š”๋ฐ๋งŒ 1024 ๋ฐ”์ดํŠธ๋ฅผ ๋‹ค ์“ฐ๊ณ  ๋ฉ”์‹œ์ง€๋Š” ์งค๋ ค๋ฒ„๋ฆฌ๋Š” ๊ฑฐ์ฃ .

@dimohy ๋‹˜๊ป˜์„œ ์ œ์‹œํ•ด ์ฃผ์‹  ์†”๋ฃจ์…˜๋Œ€๋กœ ๊ธธ์ด๋ฅผ ๋งž์ถฐ์ฃผ์‹œ๋ฉด ๋  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

PacketBuilder ํด๋ž˜์Šค

public void WriteMessage(string msg)
{
    var encodedMessage = Encoding.Default.GetBytes(msg);

    var msgLength = encodedMessage.Length;
    _ms.Write(BitConverter.GetBytes(msgLength));
    _ms.Write(encodedMessage);
}

PacketReader ํด๋ž˜์Šค

public string ReadMessage()
{
	var length = ReadInt32();
	byte[] msgBuffer = new byte[length];
	var count = _ns.Read(msgBuffer, 0, length);
	var msg = Encoding.Default.GetString(msgBuffer, 0, count);
	return msg;
}
2๊ฐœ์˜ ์ข‹์•„์š”

์ฐธ๊ณ ๋กœ BinaryReader๋ฅผ ์ƒ์†๋ฐ›์•„ PacketReader๋กœ ๊ตฌํ˜„ํ•œ ๊ฒƒ์€ ์ง€์–‘ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๋ถˆํ•„์š”ํ•˜๊ฒŒ BinaryReader์˜ ๊ธฐ๋Šฅ์ด ๋…ธ์ถœ๋˜๋‹ˆ๊นŒ์š”. ์ด๊ฒƒ ๋Œ€์‹  MessagePacket๋˜๋Š” ChatPacket์œผ๋กœ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ณ  ๋‚ด๋ถ€์ ์œผ๋กœ BinaryReader ๋ฐ BinaryWriter๋ฅผ ์“ฐ๋Š” ๊ฒƒ์ด ๊น”๋”ํ•ฉ๋‹ˆ๋‹ค.

3๊ฐœ์˜ ์ข‹์•„์š”

๋‹ต๋ณ€ ์ฃผ์…”์„œ ์ •๋ง ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ ์ž‘์„ฑํ–ˆ๋˜ ๋‚ด์šฉ์ด send๋ฒ„ํŠผ๊ณผ ๋ณด๋‚ด์ง€๋ฉด์„œ ์‚ฌ๋ผ์ง€๊ฒŒ ๊ตฌ์—ฐํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•˜๋ฉด ๋˜๋Š”์ง€ ๋„์›€์ฃผ์‹œ๋ฉด ์•ˆ๋ ๊นŒ์š”?
Button Click event๊ฐ€ ๋ฐœ์ƒํ• ๋•Œ textbox์˜ " "๊ฐ’์ด ๋˜๋„๋ก ๋ถ€์—ฌํ•˜์˜€๋”๋‹ˆ ์ „๋ถ€๋‹ค ์—†์–ด์ง€๋”๋ผ๊ตฌ์š”โ€ฆ
๋„์›€์ฃผ์…”์„œ ์ •๋ง ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

2๊ฐœ์˜ ์ข‹์•„์š”

๋„์›€์ฃผ์…”์„œ ๋„ˆ๋ฌด ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค. ํฐ ๋„์›€์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!

์ž‘์„ฑํ–ˆ๋˜ ๋‚ด์šฉ์ด send๋ฒ„ํŠผ๊ณผ ๋ณด๋‚ด์ง€๋ฉด์„œ ์‚ฌ๋ผ์ง€๊ฒŒ ๊ตฌ์—ฐํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•˜๋ฉด ๋˜๋Š”์ง€ ๋„์›€์ฃผ์‹œ๋ฉด ์•ˆ๋ ๊นŒ์š”?
Button Click event๊ฐ€ ๋ฐœ์ƒํ• ๋•Œ textbox์˜ " "๊ฐ’์ด ๋˜๋„๋ก ๋ถ€์—ฌํ•ด๋ณด์•˜๋Š”๋ฐ ์ „์ฒด ๋‚ด์šฉ์ด ์‚ฌ๋ผ์ง€๊ฒŒ ๋˜๋”๋ผ๊ตฌ์š”โ€ฆ

2๊ฐœ์˜ ์ข‹์•„์š”

github ์†Œ์Šค๋„ ์ฐธ๊ณ ํ•ด๋ณด์‹œ๋ฉด ๋„์›€ ๋˜์‹ค ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ^^

2๊ฐœ์˜ ์ข‹์•„์š”

์š”์ฒญํ•œ ํ˜„์ƒ์„ ์ถ”์ ํ•˜๊ธฐ ์œ„ํ•ด ์กฐ๊ธˆ ์‚ดํŽด๋ดค๋Š”๋ฐ, ์ผ๋‹จ @๋ฃจ๋‚˜์‹œ์•„ ๋‹˜์˜ ๊ธ€ ๋Œ€๋กœ ์ˆ˜์ •ํ•œ ํ›„ ํ™•์ธํ•ด๋ณด์„ธ์š”.

Connectํ•  ๋•Œ ์„œ๋ฒ„์—์„œ ํด๋ผ์ด์–ธํŠธ๋กœ ์—ฐ๊ฒฐ๋œ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๋ณด๋‚ด๋Š” ๋ถ€๋ถ„์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋‹ค์Œ์˜ ์ฝ”๋“œ์—์„œ ์˜ค๋™์ž‘์„ ํ•ฉ๋‹ˆ๋‹ค.

image

3๊ฐœ์˜ ์ข‹์•„์š”

๋„ต ํ•ด๊ฒฐ ํ–ˆ์Šต๋‹ˆ๋‹ค! ์„ค๋ช…ํ•ด์ฃผ์‹  BinaryReader๋ฅผ ์ƒ์†๋ฐ›์•„ PacketReader ์‚ฌ์šฉํ•˜์ง€ ๋ง๊ณ  MessagePacket ์ด๋‚˜ ChatPacket๊ฐ™์€ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์„œ ์‚ฌ์šฉํ•˜๋ผ๊ณ  ํ•˜์‹  ๋ถ€๋ถ„์— ๋Œ€ํ•ด์„œ ์ œ๊ฐ€ ์ž˜ ์ดํ•ด๊ฐ€ ์•ˆ๋ผ์„œ์š”
์ €๋„ ์œ ํŠœ๋ธŒ ๋ณด๋ฉด์„œ ํ•˜๋‚˜ ํ•˜๋‚˜์”ฉ ์ฒ˜๊ฐ€๋ฉด์„œ ๊ตฌํ˜„ํ•œ๊ฑฐ๋ผ์„œโ€ฆ ์ฝ”๋“œ ํ•˜๋‚˜ ํ•˜๋‚˜์”ฉ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„๋˜๊ณ  ๋™์ž‘๋˜๋Š”์ง€ ์ดํ•ดํ•˜๊ณ  ์žˆ๋Š” ์ค‘์ž…๋‹ˆ๋‹คโ€ฆ

2๊ฐœ์˜ ์ข‹์•„์š”

ViewModel์—์„œ System.ComponentModel.INotifyPropertyChanged๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์†์„ฑ์ด ๋ณ€๊ฒฝ๋˜์—ˆ์Œ์„ Notify ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

class MainViewModel : INotifyPropertyChanged
{
	private string _message;
	public string Message
	{
		get => _message;
		set { _message = value; OnPropertyChanged(); }
	}

	public MainViewModel()
	{
		// ๊ธฐํƒ€ ์ƒ๋žต
		SendMessageCommand = new RelayCommand(Send, o => !string.IsNullOrEmpty(Message));
	}

	public event PropertyChangedEventHandler? PropertyChanged;

	private void Send(object o)
	{
		if (string.IsNullOrEmpty(Message))
		{
			return;
		}
		_server.SendMessageToServer(Message);
		Message = string.Empty;
	}

	private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
	{
		PropertyChanged?.Invoke(this, new(propertyName));
	}
}

์ด๋ ‡๊ฒŒ Message์˜ Setter๋กœ ๊ฐ’์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค OnPropertyChanged ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด PropertyChanged ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋ฉด ํ•ด๋‹น ์†์„ฑ์— ๋ฐ”์ธ๋”ฉ๋œ View์—์„œ ๊ฐ’ ๋ณ€๊ฒฝ์„ ๊ฐ์ง€ํ•˜๊ณ  ๋ณ€๊ฒฝ๊ฐ’์„ ๋ฐ˜์˜ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ฐธ๊ณ ๋กœ ViewModel์—์„œ INotifyPropertyChanged ๊ตฌํ˜„์ด ์•ˆ ๋˜์–ด ์žˆ๋Š” ๊ฒฝ์šฐ WPF์˜ ๋ฐ”์ธ๋”ฉ ๊ตฌ์กฐ์ƒ Memory leak์„ ์œ ๋ฐœํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ•„์ˆ˜์ ์œผ๋กœ ๊ตฌํ˜„ํ•˜์…”์•ผ ํ•ฉ๋‹ˆ๋‹ค.
์ฐธ๊ณ  ๋งํฌ: .NET Framework: 945. C# - ๋‹ท๋„ท ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์—์„œ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ํŒจํ„ด

3๊ฐœ์˜ ์ข‹์•„์š”

์ œ๊ฐ€ ์‹œ๊ฐ„ ๋  ๋•Œ ์œ ์‚ฌํ•œ ์ฑ„ํŒ… ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ค์–ด์„œ ์†Œ์Šค์ฝ”๋“œ๋ฅผ ๊ณต์œ ํ•ด ๋ณด๋„๋ก ํ• ๊ป˜์š” ^^;

3๊ฐœ์˜ ์ข‹์•„์š”

๋ฉ”์‹œ์ง€๋ฅผ ๋‘ ๋ฒˆ ๋ณด๋ƒˆ์„ ๋•Œ๋ถ€ํ„ฐ ๋ฉ”์‹œ์ง€๋ฅผ ์ •์ƒ์ ์œผ๋กœ ๊ฐ์ง€ํ•˜๋Š” ๊ฑด, UserModel ์ƒ์„ฑ ๊ณผ์ •์—์„œ ReadMessage๋ฅผ ๋‘ ๋ฒˆ ์‹คํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. UID๋ฅผ ์ž„์˜ ๋ถ€์—ฌํ•˜๋Š” ์‹์œผ๋กœ ํ•ด๋ณด๋‹ˆ ์ฆ์ƒ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ณต์œ ํ•ด ์ฃผ์‹  ์ƒ˜ํ”Œ์—์„œ๋Š” ํ•ด๋‹น ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์•˜๋˜ ๊ฒƒ์€ ๋ฐ”์ดํŠธ ๋ฐฐ์—ด์ด 1024๋กœ ๊ณ ์ •๋˜์–ด ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— UserName์„ ์ฝ๋Š”๋ฐ 1024 ๋ฐ”์ดํŠธ๋ฅผ ์“ฐ๊ณ , ๋ฉ”์‹œ์ง€๋กœ ๋ณด๋‚ธ 1024 ๋ฐ”์ดํŠธ๊ฐ€ ์ŠคํŠธ๋ฆผ์— ๋‚จ์•„์„œ ์ด๋ฅผ UID๋กœ ์ฝ์—ˆ๊ธฐ ๋•Œ๋ฌธ์ผ ๊ฒƒ ๊ฐ™๋„ค์š”.

ํŒจํ‚ท์œผ๋กœ๋ถ€ํ„ฐ UserModel์„ ์ƒ์„ฑํ•˜๋Š” ๊ณผ์ •์„ ์ž˜ ๋‹ค๋“ฌ์–ด ๋ณด์‹œ๋ฉด ๋  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

3๊ฐœ์˜ ์ข‹์•„์š”

๊ผญ ๋ถ€ํƒ๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค,
ํฐ ๋„์›€ ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

3๊ฐœ์˜ ์ข‹์•„์š”

๋ฃจ๋‚˜์‹œ์•„๋‹˜ ๊ณผ dimohy๋‹˜ ๋•๋ถ„์— ํฐ ๋„์›€ ๋ฐ›์•„๊ฐ‘๋‹ˆ๋‹ค.
์„ฑ์‹ฌ์„ฑ์˜๊ป ์งˆ๋ฌธ์— ์‘๋‹ตํ•ด์ฃผ์‹œ๊ณ  ์•Œ๋ ค์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค~

3๊ฐœ์˜ ์ข‹์•„์š”

์ฐธ๊ณ  ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ƒ˜ํ”Œ ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ค์–ด๋ดค์Šต๋‹ˆ๋‹ค.

์ž์ž˜ํ•œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋Š” ํ•˜์ง€ ์•Š์•˜์œผ๋ฉฐ, ์ฑ„ํŒ… ๊ธฐ๋Šฅ๋งŒ ์ง‘์ค‘ํ•˜๊ณ  ๋‚˜๋จธ์ง€ ๊ธฐ๋Šฅ์€ ๋™์ž‘์„ฑ๋งŒ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ฐ„์†Œํ™” ํ•˜์˜€์Šต๋‹ˆ๋‹ค.,

| ์ตœ์ดˆ ํ™”๋ฉด
image

| test ์—ฐ๊ฒฐ
image

| ๋””๋ชจ์ด ์—ฐ๊ฒฐ
image

| ์„œ๋ฒ„ ํ™”๋ฉด
image

| ๋Œ€ํ™”
image

ํŒจํ‚ท์„ ์ฃผ๊ณ  ๋ฐ›๋Š” ๊ธฐ๋Šฅ์„ ChatPacket.cs์—์„œ ์ฒ˜๋ฆฌํ•˜์˜€์Šต๋‹ˆ๋‹ค.

| ํŒจํ‚ท ๋ฐ›๊ธฐ

    public static async Task<IChatPacket> ReceiveAsync(Stream s)
    {
        try
        {
            var temp = new byte[1];
            await s.ReadExactlyAsync(temp, 0, 1);

            var command = (CommandType)temp[0];
            IChatPacket result = command switch
            {
                CommandType.REQ_HELLO => ChatHelloRequest.Receive(s),
                CommandType.RES_HELLO => ChatHelloResponse.Receive(s),
                CommandType.REQ_GOODBYE => ChatGoodbyeRequest.Receive(s),
                CommandType.RES_GOODBYE => ChatGoodbyeResponse.Receive(s),
                CommandType.REQ_MESSAGE => ChatMessageRequest.Receive(s),
                CommandType.RES_MESSAGE => ChatMessageResponse.Receive(s),
                CommandType.EVT_MESSAGE => ChatMessageEvent.Receive(s),
                CommandType.EVT_INFO => ChatInfoEvent.Receive(s),
                _ => new ChatPacketError(ChatPacketErrorKind.InvalidCommand)
            };

            return result;
        }
        // ๊ฐ•์ œ ์—ฐ๊ฒฐ ์ข…๋ฃŒ
        catch (EndOfStreamException)
        {
            return new ChatPacketError(ChatPacketErrorKind.ForceDisconnected);
        }
        // ๊ธฐํƒ€ ์•Œ์ˆ˜ ์—†๋Š” ์ด์œ  (ํŒจํ‚ท ๋น„์ •์ƒ)
        catch (Exception)
        {
            return new ChatPacketError(ChatPacketErrorKind.InvalidPacket);
        }
    }

| ํŒจํ‚ท ๋ณด๋‚ด๊ธฐ

    public static void Send(IChatPacket packet, NetworkStream s)
    {
        s.WriteByte((byte)packet.Command);
        packet.Send(s);
        s.Flush();
    }

์ฃผ๊ฑฐ๋‹ˆ ๋ฐ›๊ฑฐ๋‹ˆ ํ•˜๋Š” ํŒจํ‚ท์˜ ์ข…๋ฅ˜๋Š” 1 ๋ฐ”์ดํŠธ์˜ Command๋กœ ๊ตฌ๋ถ„ํ•˜์˜€์œผ๋ฉฐ ๊ฐ๊ฐ์˜ ํŒจํ‚ท์€ IChatPacket ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

public interface IChatPacket
{
    CommandType Command { get; }
    void Send(Stream s);
}

public interface IChatPacket<T> : IChatPacket
{
    abstract static T Receive(Stream s);
}

๋‹ค์Œ์€ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ด๋Š” ํŒจํ‚ท์˜ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. (ํŒจํ‚ท ๊ตฌ์„ฑ์€ BinaryReader, BinaryWriter๋ฅผ ์ด์šฉ)

| ChatMessageRequest

public record ChatMessageRequest(string Authtoken, string Message) : IChatPacket<ChatMessageRequest>
{
    public CommandType Command => CommandType.REQ_MESSAGE;

    public static ChatMessageRequest Receive(Stream s)
    {
        using var br = new BinaryReader(s, Encoding.UTF8, true);
        return new ChatMessageRequest(br.ReadString(), br.ReadString());
    }

    public void Send(Stream s)
    {
        using var bw = new BinaryWriter(s, Encoding.UTF8, true);
        bw.Write(Authtoken);
        bw.Write(Message);
    }
}

ํŒจํ‚ท์€ ๋น„๋™๊ธฐ ๋ฉ”์†Œ๋“œ์ธ ReceivedAsync()์— ์˜ํ•ด ์ˆ˜์‹ ๋˜๋ฉฐ ์ตœ์ดˆ ์—ฐ๊ฒฐ์‹œ ๋“ฑ๋ก๋ฉ๋‹ˆ๋‹ค.

_ = _client.ReceiveAsync();
_client.ReceivedChatPacketEvent += _client_ReceivedChatPacketEvent;

์ดํ›„ ์ด๋ฒคํŠธ๋ฅผ ํ†ตํ•ด ์ˆ˜์‹ ๋œ ํŒจํ‚ท์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

private void _client_ReceivedChatPacketEvent(object? sender, ReceivedChatPacketEventArgs e)
{
    var packet = e.Packet;

    if (packet is ChatPacketError error)
    {
        // ์—๋Ÿฌ ์ฒ˜๋ฆฌ (์ƒ๋žตํ•จ)
        return;
    }

    if (packet is ChatInfoEvent info)
    {
        if (info.InfoKind is ChatInfoKind.Users)
        {
            Users = info.InfoMap.Select(x => $"{x.Value}({x.Key})").ToList();
        }
    }
    else if (packet is ChatHelloResponse response)
    {
        // ์ธ์ฆํ‚ค ์ฒ˜๋ฆฌ (์ƒ๋žตํ•จ)
    }
    else if (packet is ChatMessageEvent message)
    {
        if (_lastDate != DateOnly.FromDateTime(DateTime.Now))
        {
            _lastDate = DateOnly.FromDateTime(DateTime.Now);
            Messages += $"[{_lastDate}]\r\n";
        }

        Messages += $"[{TimeOnly.FromDateTime(DateTime.Now)}, {message.Nickname}] {message.Message}\r\n";
    }
            
    _ = e.Client.ReceiveAsync();
}

์ฐธ๊ณ ๊ฐ€ ๋˜์—ˆ์œผ๋ฉด ํ•˜๋„ค์š”.

8๊ฐœ์˜ ์ข‹์•„์š”

์นœ์ ˆํ•˜๊ฒŒ ์•Œ๋ ค์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.
๋น„๊ตํ•ด๋ณด๋ฉด์„œ ๊ณต๋ถ€ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค!

3๊ฐœ์˜ ์ข‹์•„์š”