C# Rookiss Part4 ๊ฒ์์๋ฒ : Listener
๐โโ๏ธListener
๋ฌธ์ง๊ธฐ๋ฅผ ๋ฐ๋ก ๋นผ์!
- Accept, Receive, Send ๋ฑ ๋ชจ๋ ์ ์ถ๋ ฅ ํจ์๋ค์ ๋น๋๊ธฐ ๋ฐฉ์์ผ๋ก ํด์ผ ๋จ
-
์ผ๋จ ์์ฝ์ ํด๋๊ณ ์๋์ด ๋ค์ด์ค๋ฉด ์๋ํ๊ฒ ๋ ๋ง๋ค๊ธฐ (์ด๋ฒคํธ ๋ฐฉ์)
- ๋์ ์์
- ์ฒ์์๋ ๋์๋๋ฅผ ์ง์ ๋์ง๊ธฐ
- ์ ์ง์ด ๋ฐ๋ก ์ค๋ฉด ๋ฐ๋ก ํ ์ผํ๊ธฐ
- ์ ์ง์ด ์์ค๋ฉด ์ฌ๋๊น์ง ๊ธฐ๋ค๋ฆฌ๋ค๊ฐ ์ค๋ฉด ํ ์ผํ๊ธฐ
- ํ ์ผ์ด ๋๋ฌ์ผ๋ฉด ๋ค์ ๋์๋ ๋์ง๊ธฐ
ServerCore๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ๋ฐ๋
args.Completed += new EventHandler<SocketAsyncEventArgs>(OnAccepteCompleted);
์ ๋ชจ๋ฅด๋ ๋ถ๋ถ
=> ๊ทธ๋ฅ ์ด๋ ๊ฒ ์ฐ๋๊ฑด๊ฐ๋ค ํด์ผ๋จ
๊ฒ์์๋ ๋น๋๊ธฐํจ์๋ฅผ ์จ์ผํ๋ค - Accept => AcceptAsync
Async๊ณ์ด์ ํจ์๋ค์ ๊ทธ ํ๋์ ํ๋ ์ํ๋ ์ผ๋จ ๋ฆฌํด์ ํจ -> ์ผ์ ์ํ์ ๋ ์ผ๋จ ๋น ์ ธ๋๊ฐ์ผ๋๊น ๋ค์ ์๋ ค์ค์ผํจ ( ์ด๋ฒคํธ ๋ฐฉ์) ์ผ์ ์์ฒญํ๋ ๋ถ๋ถ๊ณผ ์ค์ ์ผ์ ํ๋ ๋ถ๋ถ์ผ๋ก ๋๋๋ค - RegisterAccept, OnAcceptCompleted
pending = ๋ฏธ๊ฒฐ์ ์ pending == false ์คํ๊ณผ ๊ฑฐ์ ๋์์ ํด๋ผ์์ ์ ์์ด ์จ ๊ฒฝ์ฐ
args.Completed ๋ EventHandler๋ฐฉ์์ผ๋ก ์ด๋ฒคํธ ๋ฐฉ์์ผ๋ก ์ฝ๋ฒก์ผ๋ก ์ ๋ฌํ๋ ๋ฐฉ์
Action
Async๊ณ์ด์ ํจ์๋ค์ ๋น์ฅ์ ๊ฐ์ ๋ฝ์์ฌ ์๊ฐ ์๊ธฐ ๋๋ฌธ์ SocketAsyncEventArgs๊ฐ ์ด๋ฐ์ ๋ฐ ์ ๋ณด๋ค์ ๊ฐ์ ธ์์ ์ ๋ฌํด์ฃผ๋ ๋๋
ํ๋ก๊ทธ๋จ์์ Socket์ ์ธ์๋ก ๋ฐ๋ ํจ์๋ฅผ ๋ง๋ค์ด์ Init(IPEndPoint, Action
๐ชListener๋ถ์
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); // ๋ฐ์ธ๋ ๊ฒฐํฉ
// ์์
์์
// BackLog : ์ต๋ ๋๊ธฐ์
_listenSocket.Listen(10); // ์ผ๊พผ ์ ์ค์
SocketAsyncEventArgs args = new SocketAsyncEventArgs(); // ์ด๋ฒคํธ ํ์ ์์ ์์ฑ
args.Completed += new EventHandler<SocketAsyncEventArgs>(OnAcceptCompleted); // ์ปดํ๋ฆฟ ๊ตฌ๋
์ ์ฒญ
RegisterAccept(args); // ์ฒซ ๋์๋ ๋์ง๊ธฐ
}
void RegisterAccept(SocketAsyncEventArgs args) // ์ด์
๋ฑ๋กํ๊ธฐ ํจ์, ์ด๋ฒคํธํธ๋ค๋ฌ ๋๋งค SocketAsyncEventArgs args ์ธ์๊ฐ ํ์
{
args.AcceptSocket = null; // ๋๋ฒ์งธ ํด๋ถํฐ ๋จ์์๋ ๊ฐ์ผ๋ก ์๋ฌ๋๊ธฐ ๋๋ฌธ์ ์ด๊ธฐํ ์์ผ์ฃผ๊ธฐ
bool pending = _listenSocket.AcceptAsync(args); // ๋น๋๊ธฐ ํจ์๋ก ํฌ๋ฉ ์ ๋ฌดํ์ธ
if (pending == false) // ํฌ๋ฉ์ด ์๋ค๋ ๊ฑด ๋์๋๋ฅผ ๋ฃ์๋ง์ ๋ฌผ๊ณ ๊ธฐ๊ฐ ๋์ด๋ ๊ฒ
OnAcceptCompleted(null, args);
}
void OnAcceptCompleted(object sender, SocketAsyncEventArgs args) // ์ด๋ฒคํธํธ๋ค๋ฌ ๋๋งค object sender, SocketAsyncEventArgs args ์ธ์๊ฐ ํ์
{
if (args.SocketError == SocketError.Success) // ์๋ฌ๊ฐ ์์ด ์ ์ฑ๊ณตํ์ ๋
{
_onAcceptHandler.Invoke(args.AcceptSocket); // ์๋ฒ์ฝ์ด์ ์๋ ์ผ ์ํค๊ธฐ (์ด๋ฒคํธ ๋ฐ์ก)
}
else
Console.WriteLine(args.SocketError.ToString()); // ๋ฌด์จ ์๋ฌ์ธ์ง ํ์ธํ๊ธฐ
RegisterAccept(args); // ๋ค๋๋ฌ์ผ๋ฉด ๋ค์ ๋์๋ ๋์ง๊ธฐ
}
}
args.Completed += new EventHandler<SocketAsyncEventArgs>(OnAcceptCompleted); // ์ด์ฑํฌ๋ฅผ ๋ง๋ค๊ณ ์ด์ฑํฌ์๊ท๋จผ์ธ ๋ฅผ ๋ฃ์ด์ค๊ฒฝ์ฐ ์ฝ๋ฐฑํจ์๋ ๋ณ๋์ ์ฐ๋ ๋๊ฐ ์์ฑ
void OnAcceptCompleted(object sender, SocketAsyncEventArgs args) // ๋ ๋์กด, ์ฐ๋ ๋๋ ํ
์คํฌ๋ฅผ ๋ง๋ค์ง ์์์ง๋ง ์๋์ ์ผ๋ก ํ์์ ์์ฑํด์ ์ฌ์ฉํจ
๐ชListner, DummyClient, ServerCore ์ ์ฒด ์ฝ๋
- Listner
namespace ServerCore { 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); // ์์ ์์ // BackLog : ์ต๋ ๋๊ธฐ์ _listenSocket.Listen(10); SocketAsyncEventArgs args = new SocketAsyncEventArgs(); args.Completed += new EventHandler<SocketAsyncEventArgs>(OnAcceptCompleted); RegisterAccept(args); } void RegisterAccept(SocketAsyncEventArgs args) { args.AcceptSocket = null; bool pending = _listenSocket.AcceptAsync(args); if (pending == false) OnAcceptCompleted(null, args); } void OnAcceptCompleted(object sender, SocketAsyncEventArgs args) { if (args.SocketError == SocketError.Success) { _onAcceptHandler.Invoke(args.AcceptSocket); } else Console.WriteLine(args.SocketError.ToString()); RegisterAccept(args); } public Socket Accept() { return _listenSocket.Accept(); } } }
- DummyClient
namespace DummyClient { class Program { static void Main(string[] args) { while (true) { // DNS (Domain Name System) string host = Dns.GetHostName(); IPHostEntry ipHost = Dns.GetHostEntry(host); IPAddress ipAddr = ipHost.AddressList[0]; IPEndPoint endPoint = new IPEndPoint(ipAddr, 7777); // ํด๋ํฐ ์ค์ 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 World!"); int sendBytes = 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(500); } } } }
- ServerCore
namespace ServerCore { class Program { static Listener _listener = new Listener(); 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(e.ToString()); } } static void Main(string[] args) { // DNS (Domain Name System) string host = Dns.GetHostName(); IPHostEntry ipHost = Dns.GetHostEntry(host); IPAddress ipAddr = ipHost.AddressList[0]; IPEndPoint endPoint = new IPEndPoint(ipAddr, 7777); _listener.Init(endPoint, OnAcceptHandler); Console.WriteLine("Listening..."); while (true) { ; } } } }