using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace ServerCore
{
class Listener
{
Socket _listenSocket;
Action<Socket> _onAcceptHandler; // Accept ์๋ฃ ์ ์คํํ ํจ์
public void Init(IPEndPoint endPoint, Action<Socket> onAcceptHandler)
{
// ๋ฌธ์ง๊ธฐ ๊ต์ก
_listenSocket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
_onAcceptHandler += onAcceptHandler;
// ์์
์์
// ์ต๋ ๋๊ธฐ์
_listenSocket.Listen(10); // ์ต๋ ๋๊ธฐ ํ ํฌ๊ธฐ ์ค์
SocketAsyncEventArgs args = new SocketAsyncEventArgs();
args.Completed += new EventHandler<SocketAsyncEventArgs>(OnAcceptCompleted);
// ์ต์กฐ ํ๋ฒ์ ๋ฑ๋ก์ ํด์ค์ผํจ
RegisterAccept(args);
}
void RegisterAccept(SocketAsyncEventArgs args)
{
args.AcceptSocket = null; // ์ด์ Accept ์์ผ ์ด๊ธฐํ
bool pending = _listenSocket.AcceptAsync(args); // ๋น๋๊ธฐ Accept ์คํ // ํ๋ฉ์ ๋ฑ์ด์ค
if (pending == false) // ์ฆ์ ์๋ฃ๋ ๊ฒฝ์ฐ
OnAcceptCompleted(null, args);
}
void OnAcceptCompleted(object sender, SocketAsyncEventArgs args)
{
if (args.SocketError == SocketError.Success)
{
// ์ฝ๋ฐฑ ๋ฐฉ์์ ์ด์ฉํด์ ์ธ์๋ก ๋ฐ์์ ์๋ฃ๋๋ฉด ํธ์ถ
// ํด๋ผ์ด์ธํธ Accept ์๋ฃ ํ ์ฒ๋ฆฌ
_onAcceptHandler.Invoke(args.AcceptSocket);
}
else
{
Console.WriteLine($"Accept Error: {args.SocketError}");
}
// ๋ชจ๋ ์ผ์ด ๋๋จ ๋ค์ ํด์ ์ํด ์ค๋นํด๋
RegisterAccept(args); // ๋ค์ Accept ์์ฝ (๋์์ค ๋ค์ ๋์ง๊ธฐ)
}
public Socket Accept()
{
return _listenSocket.Accept();// ๋น๋๊ธฐ ์๋ฏธ ์กฐ๊ธ ๋์ค์ ์ฒ๋ฆฌ๋ ์ ์๋ค.
// ์ด๋ค์์ผ๋ก๋ ์๋ ค์ค์ผํจ
// ๋น๋๊ธฐ๋ ๋ง์ ์ธ์ด์์ ์ฌ์ฉํจ
// ์ฐ์ ์์์ผํ ๊ฒ์ ์ค์ ๋ก ์ฒ๋ฆฌ๋๋ ๋ถ๋ถ์ด ๋๋ก ์ชผ๊ฐ์ ธ์ ๋๋ฒ ๋ง๋ค์ด์ผํจ
}
}
}
using System.Net.Sockets;
using System.Net;
using System.Text;
namespace ServerCore
{
class Program
{
static Listener _listener = new Listener();
static void OnAcceptHandler(Socket clientSocket)
{
try
{
// 1๏ธ ํด๋ผ์ด์ธํธ ๋ฐ์ดํฐ ์์
byte[] recvBuff = new byte[1024];
int recvBytes = clientSocket.Receive(recvBuff);
string recvData = Encoding.UTF8.GetString(recvBuff, 0, recvBytes);
Console.WriteLine($"[From Client] {recvData}");
// 2๏ธ ํด๋ผ์ด์ธํธ์ ์๋ต ์ ์ก
byte[] sendBuff = Encoding.UTF8.GetBytes("Welcome to MMORPG Server!");
clientSocket.Send(sendBuff);
// 3๏ธ ์์ผ ์ข
๋ฃ
clientSocket.Shutdown(SocketShutdown.Both);
clientSocket.Close();
}
catch (Exception e)
{
Console.WriteLine($"[Error] {e}");
}
}
// DNS (Domain Name System)
// IP ์ฃผ์๋ฅผ ์จ๊ฒจ์ฃผ๋ ๋๋ฉ์ธ ๋ค์์ ์ค์ ํด์ค
static void Main(string[] args)
{
string host = Dns.GetHostName();
IPHostEntry ipHost = Dns.GetHostEntry(host);
IPAddress ipAddr = ipHost.AddressList[0];
IPEndPoint endPoint = new IPEndPoint(ipAddr, 7777);
// 2๏ธโฃ Listener ์ด๊ธฐํ ๋ฐ Accept ํธ๋ค๋ฌ ๋ฑ๋ก
_listener.Init(endPoint, OnAcceptHandler);
Console.WriteLine("Server Listening...");
while (true)
{
// ์๋ฒ๊ฐ ์ข
๋ฃ๋์ง ์๋๋ก ์ ์ง
}
}
}
}
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace DummyClient
{
internal class Program
{
static void Main(string[] args)
{
// DNS
string host = Dns.GetHostName();
IPHostEntry ipHost = Dns.GetHostEntry(host);
IPAddress ipAddr = ipHost.AddressList[0];
IPEndPoint endPoint = new IPEndPoint(ipAddr, 7777);
while(true)
{
// ํด๋ํฐ ์ค์
Socket socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try
{
// ๋ฌธ์ง๊ธฐํํ
์
์ฅ ๋ฌธ์
socket.Connect(endPoint);
Console.WriteLine($"Connected to {socket.RemoteEndPoint.ToString()}");
// ๋ณด๋ธ๋ค
byte[] sendBuff = Encoding.UTF8.GetBytes("Hello Server!");
socket.Send(sendBuff);
// ๋ฐ๋๋ค
byte[] recvBuff = new byte[1024];
int recvBytes = socket.Receive(recvBuff);
string recvData = Encoding.UTF8.GetString(recvBuff, 0, recvBytes);
Console.WriteLine($"[From Server] {recvData}");
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Thread.Sleep(100);
}
}
}
}
๋ณธ ๊ฐ์๋ C# ๊ธฐ๋ฐ TCP ๋คํธ์ํฌ ์๋ฒ์์ Listener ํด๋์ค๋ฅผ ํตํด ๋น๋๊ธฐ ์์ผ ์์ ๊ตฌ์กฐ๋ฅผ ์ค๊ณํ๋ ๋ฐฉ๋ฒ์ ํ์ตํ๋ค.
ํนํ SocketAsyncEventArgs์ AcceptAsync() ๋ฉ์๋๋ฅผ ํ์ฉํ ๋น๋๊ธฐ Accept ์ฒ๋ฆฌ,
Completed ์ด๋ฒคํธ, ์ฝ๋ฐฑ ๊ตฌ์กฐ๋ก ๋ถ๋ฆฌ๋ ์์ ์ฒ๋ฆฌ ๋ฐฉ์, ๋ฐ๋ณต ๋ฑ๋ก ๊ธฐ๋ฐ์ ๋น๋๊ธฐ ๋ฃจํ ๊ตฌ์กฐ์ ๋ํด ์ฒ ์ ํ ๋ถ์ํ๋ค.
Listener ํด๋์ค์ ์ค์ ์๋ฒ ์คํ ๊ตฌ์กฐ์ธ Program.cs ๊ฐ์ ์ฐ๊ฒฐ ๋ฐฉ์์ ํ์ตํ๋ค.
Action<Socket> ํ์์ ์ฝ๋ฐฑ ๋ฑ๋ก๊ณผ, ํด๋ผ์ด์ธํธ ์ ์ ์ ๋ฐ์ดํฐ ์์ /์ก์ /์ข
๋ฃ ํ๋ฆ์ ๊ตฌํํ๋ OnAcceptHandler(),
DummyClient๋ฅผ ํตํ ๋ฐ๋ณต ํ
์คํธ ํ๊ฒฝ๊น์ง ๊ตฌ์ฑํ๋ค.
์ด ํ๋ฆ์ ํตํด ์๋ฒ์ ํด๋ผ์ด์ธํธ ๊ฐ ๋น๋๊ธฐ ์์ผ ์ฒ๋ฆฌ์ ์์ ํ ์ฐ๋ ๊ตฌ์กฐ๋ฅผ ํ์ ํ๋ค
Accept() ํจ์๋ Blocking ํจ์๋ก, ํด๋ผ์ด์ธํธ๊ฐ ์ ์ํ์ง ์์ผ๋ฉด ๋ฌดํ ๋๊ธฐ ์ํ๊ฐ ๋๋ค.AcceptAsync()์ SocketAsyncEventArgs๋ฅผ ํ์ฉํ ์ด๋ฒคํธ ๊ธฐ๋ฐ ๋น๋๊ธฐ ์์ ์ฒ๋ฆฌ ๋ฐฉ์์ด ํ์์ ์ด๋ค.Socket>)๋ฅผ ํตํด ์ฒ๋ฆฌ๋๋ค.| ์ฉ์ด | ์ค๋ช |
|---|---|
| Listener ์์ผ | ํด๋ผ์ด์ธํธ์ ์ ์ ์์ฒญ์ ๋ฐ๊ธฐ ์ํด ์๋ฒ ์ธก์ ์์ ์ด๋ ค ์๋ ์์ ์ ์ฉ ์์ผ |
| Accept | ํด๋ผ์ด์ธํธ์ ์ฐ๊ฒฐ์ ์๋ฝํ๊ณ ์๋ก์ด ํต์ ์ฉ ์์ผ์ ๋ฐํํ๋ ๊ณผ์ |
| AcceptAsync() | Accept ์์ ์ ๋น๋๊ธฐ์ ์ผ๋ก ์ฒ๋ฆฌํ๋ฉฐ, ๊ฒฐ๊ณผ๋ ์ด๋ฒคํธ๋ก ํต๋ณด๋ฐ์ |
| SocketAsyncEventArgs | AcceptAsync ๋ฑ ๋น๋๊ธฐ ์์ผ ํจ์์ ์ํ๋ฅผ ๋ด๋ ์ด๋ฒคํธ ๊ฐ์ฒด |
| Completed ์ด๋ฒคํธ | AcceptAsync๊ฐ ์๋ฃ๋์์ ๋ ํธ์ถ๋๋ ์ฝ๋ฐฑ ํจ์ ๋ฑ๋ก ์์น |
| RegisterAccept() | ๋ค์ ํด๋ผ์ด์ธํธ ์ฐ๊ฒฐ์ ์ํ AcceptAsync ๋ฑ๋ก ํจ์ |
| Pending | AcceptAsync๊ฐ ์ฆ์ ์๋ฃ๋์ง ์๊ณ ๋์ค์ ์๋ฃ๋ ์์ ์ด๋ผ๋ ์ํ |
Action<Socket> | ์์ผ์ ์ธ์๋ก ๋ฐ๋ ๋ธ๋ฆฌ๊ฒ์ดํธ(์ฝ๋ฐฑ ํจ์) |
| Invoke() | ๋ฑ๋ก๋ Action์ ์คํํ๋ ๋ฉ์๋ |
| OnAcceptHandler() | ํด๋ผ์ด์ธํธ ์ ์ ์ดํ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ๋ฐ ์ข ๋ฃ๋ฅผ ์ํํ๋ ์ค์ ํจ์ |
| DummyClient | ์๋ฒ ์์ ์ฒ๋ฆฌ๋ฅผ ํ ์คํธํ๊ธฐ ์ํ ์๋ ์ ์ ํด๋ผ์ด์ธํธ ํ๋ก๊ทธ๋จ |
public class Listener
{
Socket _listenSocket;
Action<Socket> _onAcceptHandler;
public void Init(IPEndPoint endPoint, Action<Socket> onAcceptHandler)
{
_listenSocket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
_onAcceptHandler += onAcceptHandler;
_listenSocket.Bind(endPoint); // ๋ฌธ์ง๊ธฐ ๊ต์ก
_listenSocket.Listen(10); // ์์
์์
SocketAsyncEventArgs args = new SocketAsyncEventArgs();
args.Completed += new EventHandler<SocketAsyncEventArgs>(OnAcceptCompleted);
RegisterAccept(args); // ์ต์ด ๋์์ค ๋์ง๊ธฐ
}
Init() ํจ์๋ ์๋ฒ ์์ ์ ํธ์ถ๋๋ฉฐ,SocketAsyncEventArgs ๊ฐ์ฒด๋ Accept ์์
์ ์ํ ์ ์ฅ ๋ฐ ์๋ฃ ์ด๋ฒคํธ ์ฒ๋ฆฌ ์ญํ ์ ํ๋ค.args.Completed += ... ๊ตฌ๋ฌธ์ ๋น๋๊ธฐ Accept๊ฐ ์๋ฃ๋์์ ๋ ํธ์ถ๋ ์ฝ๋ฐฑ ํจ์๋ฅผ ๋ฑ๋กํ๋ ๊ณผ์ ์ด๋ค. void RegisterAccept(SocketAsyncEventArgs args)
{
args.AcceptSocket = null; // ์ด์ ํด๋ผ์ด์ธํธ ์์ผ ์ ๊ฑฐ
bool pending = _listenSocket.AcceptAsync(args); // ๋น๋๊ธฐ ์์ ์์ฒญ
if (pending == false)
{
// ๋ฐ๋ก ์๋ฃ๋์์ ๊ฒฝ์ฐ ์ง์ ์ฝ๋ฐฑ ํธ์ถ
OnAcceptCompleted(null, args);
}
}
AcceptAsync()๋ ํธ์ถ ์ฆ์ true ๋๋ false๋ฅผ ๋ฐํํ๋ค.true: ์์ง ํด๋ผ์ด์ธํธ๊ฐ ์๊ณ , ๋์ค์ Completed ์ด๋ฒคํธ๊ฐ ํธ์ถ๋ ์์ false: ์ด๋ฏธ ํด๋ผ์ด์ธํธ๊ฐ ๋ถ์ด ์์ด ์ฆ์ ์๋ฃ โ ์๋์ผ๋ก OnAcceptCompleted() ํธ์ถ ํ์args.AcceptSocket = null์ ์ด์ Accept ์์
์ ํด๋ผ์ด์ธํธ ์์ผ ์ ๋ณด๋ฅผ ์ ๊ฑฐํ๋ ํ์ ์ฒ๋ฆฌ์ด๋ค."SocketAsyncEventArgs ์ด๋ฏธ ์์ผ์ด ์ฐ๊ฒฐ๋์ด ์์ต๋๋ค" ์ค๋ฅ ๋ฐ์ void OnAcceptCompleted(object sender, SocketAsyncEventArgs args)
{
if (args.SocketError == SocketError.Success)
{
// ์ธ๋ถ์์ ์ ๋ฌ๋ฐ์ ํด๋ผ์ด์ธํธ ์ฒ๋ฆฌ ํจ์ ์คํ
_onAcceptHandler.Invoke(args.AcceptSocket);
}
else
{
Console.WriteLine($"Accept Error: {args.SocketError}");
}
// ๋ค์ ํด๋ผ์ด์ธํธ๋ฅผ ์ํด ๋ค์ ๋์์ค ๋ฑ๋ก
RegisterAccept(args);
}
}
OnAcceptCompleted()๋ AcceptAsync๊ฐ ์๋ฃ๋์์ ๋ ์๋ ํธ์ถ๋๋ ์ฝ๋ฐฑ ํจ์๋ค.args.SocketError๊ฐ ์ฑ๊ณต์ผ ๊ฒฝ์ฐ, args.AcceptSocket์ ํด๋ผ์ด์ธํธ์ ์ฐ๊ฒฐ๋ ์ธ์
์์ผ์ด ๋ด๊ฒจ ์๋ค._onAcceptHandler.Invoke()๋ฅผ ํตํด ์ธ๋ถ ์ฒ๋ฆฌ ๋ก์ง(์: ๋ฐ์ดํฐ ์์ )์ผ๋ก ์ ๋ฌ๋๋ค.RegisterAccept()๋ฅผ ํธ์ถํ์ฌ ๋ค์ ํด๋ผ์ด์ธํธ ์ ์ ๋๊ธฐ๋ฅผ ์ด์ด๊ฐ๋ค.[Init()]
โ
RegisterAccept(args) โ ๋์๋๋ฅผ ๋์ง๋ค
โ
ํด๋ผ์ด์ธํธ ์ ์
โ
AcceptAsync ์๋ฃ
โ
OnAcceptCompleted() โ ๋ฌผ๊ณ ๊ธฐ ์ก์๋ค
โ
_onAcceptHandler() โ ์๋ ์๋
โ
RegisterAccept(args) โ ๋ค์ ์๋ ๊ธฐ๋ค๋ฆผ
Program.cs ๊ตฌ์กฐstatic void Main(string[] args)
{
string host = Dns.GetHostName();
IPHostEntry ipHost = Dns.GetHostEntry(host);
IPAddress ipAddr = ipHost.AddressList[0];
IPEndPoint endPoint = new IPEndPoint(ipAddr, 7777);
_listener.Init(endPoint, OnAcceptHandler); // Listener ์ด๊ธฐํ ๋ฐ ์ฝ๋ฐฑ ๋ฑ๋ก
Console.WriteLine("Server Listening...");
while (true)
{
; // ์๋ฒ๊ฐ ์ข
๋ฃ๋์ง ์๋๋ก ์ ์ง
}
}
Init() ํธ์ถ์ ํตํด Listener๊ฐ ์์ผ ์์ฑ, ๋ฐ์ธ๋ฉ, Listen, AcceptAsync ๋ฑ๋ก์ ์ํOnAcceptHandler๋ฅผ ์ ๋ฌ โ Accept๊ฐ ์๋ฃ๋์์ ๋ ์คํ๋ ํด๋ผ์ด์ธํธ ์ฒ๋ฆฌ ๋ก์ง์ ๋๊ธด ๊ฒstatic void OnAcceptHandler(Socket clientSocket)
{
try
{
byte[] recvBuff = new byte[1024];
int recvBytes = clientSocket.Receive(recvBuff);
string recvData = Encoding.UTF8.GetString(recvBuff, 0, recvBytes);
Console.WriteLine($"[From Client] {recvData}");
byte[] sendBuff = Encoding.UTF8.GetBytes("Welcome to MMORPG Server!");
clientSocket.Send(sendBuff);
clientSocket.Shutdown(SocketShutdown.Both);
clientSocket.Close();
}
catch (Exception e)
{
Console.WriteLine($"[Error] {e}");
}
}
Receive()๋ก ์์ ์ฒ๋ฆฌwhile (true)
{
Socket socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try
{
socket.Connect(endPoint);
Console.WriteLine($"Connected to {socket.RemoteEndPoint}");
byte[] sendBuff = Encoding.UTF8.GetBytes("Hello Server!");
socket.Send(sendBuff);
byte[] recvBuff = new byte[1024];
int recvBytes = socket.Receive(recvBuff);
string recvData = Encoding.UTF8.GetString(recvBuff, 0, recvBytes);
Console.WriteLine($"[From Server] {recvData}");
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Thread.Sleep(100); // 0.1์ด๋ง๋ค ๋ฐ๋ณต ์ ์
}
AcceptAsync()๊ฐ ๋น๋๊ธฐ๋ก ์ ๋ฑ๋ก๋์ด ์๋ค๋ฉด ๋๊น ์์ด ๋ชจ๋ ์์ฒญ์ ์ฒ๋ฆฌ ๊ฐ๋ฅ[Main()]
โ
_listener.Init(endpoint, OnAcceptHandler) โ ์ฝ๋ฐฑ ๋ฑ๋ก
โ
RegisterAccept(args) โ ๋์๋ ๋์ง
โ
ํด๋ผ์ด์ธํธ ์ ์ (DummyClient)
โ
AcceptAsync ์๋ฃ
โ
OnAcceptCompleted()
โ
_onAcceptHandler.Invoke(socket)
โ
Receive, Send, Close
โ
๋ค์ RegisterAccept(args)
| ํญ๋ชฉ | ๋ด์ฉ |
|---|---|
| Listener ํด๋์ค | ํด๋ผ์ด์ธํธ ์ ์์ ์์ ํ๊ณ , ์ธ๋ถ ์ฝ๋ฐฑ์ผ๋ก ์ฐ๊ฒฐ ์ฒ๋ฆฌ ์์ |
| AcceptAsync | ๋น๋๊ธฐ Accept ์์ฒญ ํจ์๋ก, ์์ ์๋ฃ ์ ์ด๋ฒคํธ ๋ฐ์ |
| SocketAsyncEventArgs | AcceptAsync์ ์ํ ๋ณด๊ด + ์ด๋ฒคํธ ์ ๋ฌ ๊ฐ์ฒด |
| RegisterAccept | ํด๋ผ์ด์ธํธ ์์ ๋๊ธฐ ๋ฑ๋ก (๋์์ค ๋์ง๊ธฐ) |
| OnAcceptCompleted | Accept ์๋ฃ ์ ์ฝ๋ฐฑ ํจ์๋ก ํด๋ผ์ด์ธํธ ์์ผ ์ฒ๋ฆฌ |
| ๋ฐ๋ณต ํ๋ฆ | RegisterAccept โ AcceptAsync โ OnAcceptCompleted โ ๋ค์ RegisterAccept |
| ์ฝ๋ฐฑ ๋ฑ๋ก ๊ตฌ์กฐ | Listener๋ ํด๋ผ์ด์ธํธ ์ฐ๊ฒฐ ์ดํ์ ๋ก์ง์ ์ธ๋ถ์ ์์ํจ |
| OnAcceptHandler | ์ค์ ๋ฐ์ดํฐ ์ก์์ ๋ฐ ์ฐ๊ฒฐ ์ข ๋ฃ ์ฒ๋ฆฌ ๋ด๋น |
| DummyClient | ๋ฐ๋ณต ์ ์ ํ ์คํธ๋ก Listener ๊ตฌ์กฐ์ ์์ ์ฑ ๊ฒ์ฆ |
| ํ๋ฆ ๋ฐ๋ณต | AcceptAsync โ ์๋ฃ โ _onAcceptHandler ์คํ โ RegisterAccept ์ฌ๋ฑ๋ก |