using System.Net;
using System.Net.Sockets;
using System.Text;
using ServerCore;
namespace Server
{
class Program
{
static Listener _listener = new Listener();
public static GameRoom Room = new GameRoom();
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, () => { return SessionManager.instance.Generate(); });
Console.WriteLine("Listening.... ");
while (true)
{
}
}
}
}
using ServerCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Server
{
class GameRoom : IJobQueue
{
List<ClientSession> _sessions = new List<ClientSession>();
JobQueue _jobQueue = new JobQueue();
public void Push(Action job)
{
_jobQueue.Push(job);
}
public void Broadcast(ClientSession session, string chat)
{
S_Chat packet = new S_Chat();
packet.playerId = session.SessionId;
packet.chat = $"{chat} I am {packet.playerId}";
ArraySegment<byte> segment = packet.Write();
// 서버가 각 세션에 chat 뿌림 N^2
foreach (ClientSession s in _sessions)
{
s.Send(segment);
}
}
public void Enter(ClientSession session)
{
_sessions.Add(session);
session.Room = this;
}
public void Leave(ClientSession session)
{
_sessions.Remove(session);
}
}
}
using ServerCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace Server
{
class ClientSession : PacketSession
{
public int SessionId { get; set; }
public GameRoom Room { get; set; }
public override void OnConnected(EndPoint endPoint)
{
Console.WriteLine($"OnConnected : {endPoint}");
Program.Room.Push(() => Program.Room.Enter(this));
}
public override void OnRecvPacket(ArraySegment<byte> buffer)
{
PacketManager.instance.OnRecvPacket(this, buffer);
}
public override void OnDisconnect(EndPoint endPoint)
{
SessionManager.instance.Remove(this);
if(Room != null)
{
GameRoom room = Room;
room.Push(() => room.Leave(this));
Room = null;
}
Console.WriteLine($"OnDisconnected : {endPoint}");
}
public override void OnSend(int numOfBytes)
{
//Console.WriteLine($"Transferred bytes: {numOfBytes}");
}
}
}
using Server;
using ServerCore;
using System;
using System.Collections.Generic;
using System.Text;
// 패킷이 조립이 다 되었으면 무엇을 호출할까를 기술
class PacketHandler
{
// 어떤 세션에서 조립이 되었는가 / 어떤 패킷인가 받아옴
// 패킷 내부 내용을 출력
// C_ : packet(client to server)
public static void C_ChatHandler(PacketSession session, IPacket packet)
{
C_Chat chatPacket = packet as C_Chat;
ClientSession clinetSession = session as ClientSession;
if (clinetSession.Room == null)
return;
GameRoom room = clinetSession.Room;
room.Push(
() => room.Broadcast(clinetSession, chatPacket.chat)
);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ServerCore
{
public interface IJobQueue
{
void Push(Action job);
}
// 내가 해야하는 행동 목록들을 들고 있음
public class JobQueue : IJobQueue
{
Queue<Action> _jobQueue = new Queue<Action>();
object _lock = new object();
bool _flush = false;
public void Push(Action job)
{
bool flush = false;
lock (_lock)
{
_jobQueue.Enqueue(job);
if (_flush == false)
flush = _flush = true;
}
if (flush)
Flush();
}
void Flush()
{
while (true)
{
Action action = Pop();
if (action == null)
return;
action.Invoke();
}
}
Action Pop()
{
lock (_lock)
{
if (_jobQueue.Count == 0)
{
_flush = false;
return null;
}
return _jobQueue.Dequeue();
}
}
}
}
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
리스너
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
{
public class Listener
{
Socket _listenSocket;
Func<Session> _sessionFactory;
public void init(IPEndPoint endPoint, Func<Session> sessionFactory, int register = 10, int backlog = 100)
{
_listenSocket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
_sessionFactory += sessionFactory;
// 문지기 교육
_listenSocket.Bind(endPoint);
// 영업 시작
// Backlog : 최대 대기 수
_listenSocket.Listen(backlog);
for(int i = 0; i < register; i++)
{
SocketAsyncEventArgs args = new SocketAsyncEventArgs();
args.Completed += new EventHandler<SocketAsyncEventArgs>(OnAccpetComplete);
RegisterAccept(args);
}
}
void RegisterAccept(SocketAsyncEventArgs args)
{
// 재사용하기때문에 이전것이 남아있으면 안되므로 null로 초기화
args.AcceptSocket = null;
bool pending = _listenSocket.AcceptAsync(args);
// 빨리 처리되어 펜딩이 일어나지 않는다면
if (pending == false)
OnAccpetComplete(null, args);
}
void OnAccpetComplete(object obj, SocketAsyncEventArgs args)
{
// 에러없이 성공 되었다면
if(args.SocketError == SocketError.Success)
{
// 클라이언트 소켓을 전달받는 부분과 동치
Session session = _sessionFactory.Invoke();
session.Start(args.AcceptSocket);
session.OnConnected(args.AcceptSocket.RemoteEndPoint);
}
else
Console.WriteLine(args.SocketError.ToString());
RegisterAccept(args);
}
}
}