C#/네트워크 관련
Socket 연결 실습 - 2
tmd1
2024. 10. 1. 22:21
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace ServerCore
{
internal class Program
{
static Listener _listener = new Listener();
static void OnAcceptHandler(Socket clientSocket)
{
// 받는다
byte[] recvBuff = new byte[1024];
int recvBytes = clientSocket.Receive(recvBuff);
string recvData = Encoding.UTF8.GetString(recvBuff, 0, recvBytes);
Console.WriteLine($"[From Data] {recvData}");
// 보낸다
byte[] sendBuff = Encoding.UTF8.GetBytes("Welcome to MMORPG Server !");
clientSocket.Send(sendBuff);
// 끝내기
clientSocket.Shutdown(SocketShutdown.Both);
clientSocket.Close();
}
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);
_listener.init(endPoint, OnAcceptHandler);
Console.WriteLine("Listening.... ");
while (true)
{
}
}
}
}
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
{
internal class Listener
{
Socket _listenSocket;
Action<Socket> _onAceeptHandler;
public void init(IPEndPoint endPoint, Action<Socket> onAceeptHandler)
{
_listenSocket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
_onAceeptHandler += onAceeptHandler;
// 문지기 교육
_listenSocket.Bind(endPoint);
// 영업 시작
// Backlog : 최대 대기 수
_listenSocket.Listen(10);
// callback 방식으로 동작시키기 위해 SocketAsyncEventArgs 객체 생성
SocketAsyncEventArgs args = new SocketAsyncEventArgs();
// args.Completed 이벤트에 OnAccpetComplete 메서드 등록
// args.Completed는 EventHandler라는 delegate의 이벤트로
// EventHandler는 object와 SocketAysncEventArgs를 매개변수로 받음
// 따라서 똑같은 매개변수를 갖는 OnAccpetComplete 메서드를 등록 가능
// 만약 비동기 Accpet가 완료된다면 신호를 보내 OnAccpetComplete 함수가
// 실행되게 됨.
args.Completed += new EventHandler<SocketAsyncEventArgs>(OnAccpetComplete);
// 직접 등록해줘서 펜딩이 일어나지 않는다면 if문에서 처리될거고
// 펜딩이 일어난다면 바로 위에서 콜백방식으로 실행됨
RegisterAccept(args);
}
void RegisterAccept(SocketAsyncEventArgs args)
{
// 재사용하기때문에 이전것이 남아있으면 안되므로 null로 초기화
args.AcceptSocket = null;
bool pending = _listenSocket.AcceptAsync(args);
// 빨리 처리되어 펜딩이 일어나지 않는다면
// 펜딩이 일어난다면 callback 방식으로 if문 내 구문이 실행되게됨
if (pending == false)
OnAccpetComplete(null, args);
}
void OnAccpetComplete(object obj, SocketAsyncEventArgs args)
{
// 에러없이 성공 되었다면
if(args.SocketError == SocketError.Success)
{
// 클라이언트 소켓을 전달받는 부분과 동치
// _OnAceeptHandler에 등록된 함수가 args.AcceptSocket을
// 매개변수로 받아 실행된다.
// 이떄 args.AccetSocket은 동기 연결 방식에서 Accpet()함수로
// 만들어졌던 클라이언트소켓과 동일함
_onAceeptHandler.Invoke(args.AcceptSocket);
}
else
Console.WriteLine(args.SocketError.ToString());
// 다시 연결을 비동기로 받아줌 -> 연결 반복
RegisterAccept(args);
}
}
}