6μ₯ κ²μ λ€νΈμν¬ μμ§ νλΌμ°λλ·
1. κ²μ μλ², λ€νΈμν¬ μμ§
κ²μ μλ²μ λ©ν°νλ μ΄μ΄ μ²λ¦¬λ₯Ό κ°λ°ν λ λ€νΈμνΉ μ²λ¦¬λ₯Ό μν΄ λ³΄ν΅ μμΌ APIλ₯Ό μ΄μ©νλ€. κ·Έλ¬λ μμΌ APIλ§ μ΄μ©νλ©΄ λ€μκ³Ό κ°μ λ²κ±°λ‘μμ΄ λ°μν μ μλ€.
- μ΄μ체μ λ§λ€ μμΌ APIλ₯Ό μ¬μ©νλ λ°©μμ μ°¨μ΄κ° μλ€.
- μμΌ APIμμ μ 곡νμ§ μλ κΈ°λ₯μ μ§μ λ§λ€μ΄μΌ νλ€.
κ·Έλμ μ΄λ¬ν λ¬Έμ λ₯Ό κ°μ νκΈ° μν΄ λ€νΈμν¬ μμ§μ μ¬μ©νκΈ°λ νλ€.
2. κ°λ° νκ²½κ³Ό κΈ°λ³Έ λͺ¨λ
λ€νΈμν¬ μμ§ μ€ νλμΈ νλΌμ°λλ·μ...
- μμ μ© μννΈμ¨μ΄λ‘ κ°μΈμ΄λ νΉμ 쑰건μ μΈλ κ°λ°μ¬μμλ 무λ£λ‘ μ¬μ©ν μ μλ€.
- ν΄λΌμ΄μΈνΈ-μλ² κ° λ€νΈμνΉκ³Ό ν΄λΌμ΄μΈνΈ κ° μ§μ λ€νΈμνΉμ λ¨μνκ² μ¬μ©ν μ μκ² νλ©° λ€νΈμν¬ μνΈν, μμΆ, νλ¦ μ μ΄ λ± κΈ°λ₯μ μ 곡νλ€.
- κ°λ° μΈμ΄λ C++, C#μ μ§μνλ€.
- μλ² λͺ¨λμ μλ μλ²μ 리λ μ€λ₯Ό μ§μνκ³ ν΄λΌμ΄μΈνΈλ μλ, 리λ μ€, iOS, μλλ‘μ΄λ, νλ μ΄μ€ν μ΄μ 4λ₯Ό μ§μνλ€.
3. κ²μ ν΄λΌμ΄μΈνΈ-μλ² ν΅μ
λ€νΈμν¬ λͺ¨λμ ν¬κ² ν΄λμ€ 2κ°λ‘ λλλ€.
- NetServer ν΄λμ€: κ²μ μλ²μ λ©μΈ λͺ¨λλ‘ ν΄λΌμ΄μΈνΈμ μ°κ²°μ λ°μΌλ©° λ©μμ§λ₯Ό μ£Όκ³ λ°λ μν μ νλ€. λ κ° ν΄λΌμ΄μΈνΈμ λ€νΈμν¬ μν© λ±μ μ΄λν μ μλ€.
- NetClient ν΄λμ€: κ²μ ν΄λΌμ΄μΈνΈμμ λ€νΈμν¬ λͺ¨λλ‘ μλ²μ μ°κ²°μ λ§Ίμ ν λ©μμ§λ₯Ό μ£Όκ³ λ°μ μ μλ€. λ λ€λ₯Έ ν΄λΌμ΄μΈνΈμ P2P ν΅μ λ κ°λ₯νλ€.
NetServer μΈμ€ν΄μ€λ₯Ό μμ±νκ³ ν΄λΌμ΄μΈνΈ μ μμ λ°μΌλ €λ©΄, λ€μ μμ μ΄ νμνλ€.
- CNetServer.Create()λ‘ μΈμ€ν΄μ€λ₯Ό μμ±νλ€.
- CNetServer.Start()λ‘ ν΄λΌμ΄μΈνΈ μ μμ λ°λλ€. μ΄λ 맀κ°λ³μλ‘ λ¦¬μ€λ ν¬νΈ λ²νΈμ νλ‘ν μ½ λ²μ μ 보λΈλ€.
- νλ‘ν μ½ λ²μ μ μλ²μ ν΄λΌμ΄μΈνΈκ° λͺ¨λ λ§μΆμ΄μΌ νλ€.
CNetServer* s = CNetServer::Create();
param.m_tcpPorts.Add(44444);
param.m_udpPorts.Add(44444);
param.m_protocolVersion = Guid(
{ 0x5dca93f4, 0x8133, 0x44a0,{ 0xb5, 0x7b,
0x75, 0x7d, 0x9c, 0x78, 0xd5, 0x2e } });
s->Start(param);
ν΄λΌμ΄μΈνΈλ μΈμ€ν΄μ€λ₯Ό μμ±νκ³ μλ²μ μ μνλ €λ©΄, λ€μ μμ μ΄ νμνλ€.
- CNetClient.Create()λ‘ μΈμ€ν΄μ€λ₯Ό μμ±νλ€.
- CNetClient.Connect()λ‘ μλ²μ μ μνλ€. μ΄λ 맀κ°λ³μλ‘ μλ² μ£Όμμ ν¬νΈ κ°, νλ‘ν μ½ λ²μ μ 보λΈλ€.
CNetClient* c = CNetClient::Create();
param.m_serverAddr = _PNT("my.game.com");
param.m_serverPort = 44444;
param.m_protocolVersion = Guid(...);
c->Connect(param);
μλ²μ ν΄λΌμ΄μΈνΈ μ μμ΄ λ€μ΄μ€λ©΄, μλ² μ€λ λ νμμ OnClientJoin() μ΄λ²€νΈ ν¨μλ₯Ό νΈμΆνλ€. OnClientJoin()μ ν΄λΌμ΄μΈνΈ μ μμ΄ λ€μ΄μμμ μ리λ μ΄λ²€νΈλ‘ ν¨μ μ½λ°± ννμ΄λ€. μ¦, μ΄λ²€νΈ ν¨μλ₯Ό μ΄μ©νλ €λ©΄, κ°λ°μλ μ΄ μ΄λ²€νΈλ₯Ό μ²λ¦¬νλ ν¨μλ₯Ό λ§λ€μ΄μΌ νκ³ νλΌμ°λλ·μ κ·Έ ν¨μλ₯Ό νΈμΆν΄ μ€λ€.
s->OnClientJoin = [](CNetClientInfo* info) {
// infoμλ μ ν΄λΌμ΄μΈνΈ μ λ³΄κ° μλ€.
...
};
μλ² μ μμ΄ μλ£λλ©΄, ν΄λΌμ΄μΈνΈμμλ OnJoinServerComplete() μ΄λ²€νΈ ν¨μλ₯Ό νΈμΆνλ€.
c->OnJoinServerComplete = [](ErrorInfo* result) {
if (result->m_errorType = = ErrorType_Ok) {
... // μ±κ³΅ μ²λ¦¬
}
else {
print(result->ToString());
... // μ€ν¨ μ²λ¦¬
}
};
μΌλ°μ μΈ κ²μ ν΄λΌμ΄μΈνΈλ λ©μΈ 루νλ₯Ό κ°μ§λ€. λ©μΈ 루νμμλ κ²μ λ‘μ§ μ²λ¦¬μ λ λλ§μ νλλ°, μλ²λ λ€λ₯Έ ν΄λΌμ΄μΈνΈμμ μ¨ λ©μμ§λ₯Ό μ²λ¦¬νκ±°λ μ΄λ²€νΈ ν¨μλ₯Ό νΈμΆλ°λ κ²λ μ΄ λ©μΈ 루ν μ΄λκ°μμ ν κ²μ΄λ€. FrameMove() ν¨μλ₯Ό νΈμΆνλ©΄, μ§κΈκΉμ§ λμ λ μ΄λ²€νΈλ μμ λ λ©μμ§μ λν μ΄λ²€νΈ μ½λ°±μ΄ μΌμ΄λλ€.
c->FrameMove();
λ€μμΌλ‘ ν΄λΌμ΄μΈνΈμ μλ² κ° μ°κ²° ν΄μ μ΄λ€.
ν΄λΌμ΄μΈνΈμμ Disconnect() ν¨μλ₯Ό νΈμΆνκ±°λ μλ²μ ν΄λΌμ΄μΈνΈ μ°κ²°μ΄ μ€κ°μ λ겨 OnLeaceServer() μ΄λ²€νΈ ν¨μκ° νΈμΆλλ©΄, μλ²μμλ OnClientLeave() μ΄λ²€νΈ ν¨μκ° νΈμΆλλ€.
c->OnLeaveServer = [](ErrorInfo* reason) {
// reasonμλ μ λμ΄μ‘λμ§κ° λ΄κ²¨ μλ€.
...
};
s->OnClientLeave = [](CNetClientInfo* client,
ErrorInfo* reason,
const ByteArray& comment) {
// μ¬κΈ°μ μ΄λ²€νΈ μ²λ¦¬ μ½λλ₯Ό μΆκ°νλ€.
};
4. λ©μμ§ μ£Όκ³ λ°κΈ°
νλΌμ°λλ·μμ λ©μμ§λ₯Ό μ£Όκ³ λ°λ λ°©λ²μ ν¬κ² 'μ ν΅μ μΈ λ°©λ²μΌλ‘ λ°μ΄λ리 λ°μ΄ν° μ£Όκ³ λ°κΈ°'μ 'λ€λ₯Έ μ»΄ν¨ν°μ μλ ν¨μλ₯Ό μ격μΌλ‘ νΈμΆνκΈ°'κ° μλ€.
μ ν΅μ μΈ λ°©λ²μΌλ‘ λ°μ΄λ리 λ°μ΄ν° μ£Όκ³ λ°κΈ°λ NetClientμ NetServer λ΄ SendUserMessage() ν¨μλ‘ μλλ°©μκ² λ©μμ§λ₯Ό μ μ‘νλ λ°©λ²μ΄λ€. μ΄λ 맀κ°λ³μλ λ€μκ³Ό κ°λ€.
- λꡬ(HostID λλ HostID array): λ©μμ§λ₯Ό 보λ΄κ³ μ νλ λμ
- μ΄λ»κ²(reliable, unreliable λ±): μ΄λ€ λ°©λ²μΌλ‘ μλλ°©μκ² λ©μμ§λ₯Ό μ μ‘ν μ§
- 무μμ(byte array): λ©μμ§
unsigned char data[100];
c->SendUserMessage(HostID_Server,
RmiContext::ReliableSend, data, 100);
s->SendUserMessage(ClientHostID,
RmiContext::UnreliableSend, data, 50);
HostID sendTo[10];
s->SendUserMessage(sendTo, 10,
RmiContext::UnreliableSend, data, 30);
λ©μμ§λ₯Ό μμ νλ©΄ OnReceiveUserMessage() μ΄λ²€νΈ ν¨μκ° νΈμΆλλ€.
c->OnReceiveUserMessage = [...]
(HostID sender, const RmiContext& rmiContext,
uint8_t* payload, int payloadLength)
{
... // μμ λ μ΄λ²€νΈ μ²λ¦¬λ₯Ό ν΄ μ£Όμ.
};
5. μμ΄νμ΄ μ λ£°λ¬ μ°κ²° νΈλμ€λ² κΈ°λ₯
λͺ¨λ°μΌ κ²μμ κ°λ°ν λλ 무μ λ€νΈμν¬κ° λμ΄μ§ μ μλ€λ μ μ κ³ λ €ν΄μΌ νλλ°, νλΌμ°λλ·μ μ°κ²° μ μ§ κΈ°λ₯μ ν΅ν΄ μ΄ λ¬Έμ λ₯Ό 극볡ν μ μλ€. μ΄λ₯Ό μ¬μ©νλ©΄ μμ΄νμ΄ μ§μμ λ²μ΄λκ±°λ λ°λλ‘ μμ΄νμ΄ μ§μ μμΌλ‘ λ€μ΄κ°λλΌλ μ°κ²°μ΄ λμ΄μ§λ νμ μμ΄ κ²μμ νλ μ΄ν μ μλ€.
param.m_autoConnectionRecovery = true;
...
c->Connect(param);
λ€νΈμν¬ ν΅μ μ΄ μΌμμ μΌλ‘ λ©μΆκ³ λ€μ ν볡λλ©΄, κ·Έλμ μ£Όκ³ λ°μ§ λͺ»νλ λ©μμ§λ₯Ό νκΊΌλ²μ λ°λλ€.
// λ€νΈμν¬κ° μΌμ μ μ§λμμ λ
c->OnServerOffline = [...](CRemoteOfflineEventArgs &args) {
// argsμλ μ μ€νλΌμΈμ΄ λμλμ§μ λν μ λ³΄κ° μλ€.
...
};
// λ€νΈμν¬κ° λ€μ ν볡λμμ λ
c->OnServerOnline = [](CRemoteOnlineEventArgs &args) {
// argsμλ μ°κ²° νΈλμ€λ²κ° μλ£λ ν μ λ³΄κ° λ΄κ²¨ μλ€.
...
};
6. μ격 λ©μλ νΈμΆ
μμ μ΄ν΄λ³Έ μ ν΅μ μΈ λ°©λ²μΌλ‘ λ°μ΄λ리 λ°μ΄ν° μ£Όκ³ λ°κΈ°λ μ‘μμ 루ν΄μ μ§μ λ§λ€μ΄μΌ νλ λ²κ±°λ‘μμ΄ μλ€. νλΌμ°λλ·μ RMI(μ격 λ©μλ νΈμΆ(Remote Method Invocation))μ μλλ°© μ»΄ν¨ν° μμ μλ νλ‘κ·Έλ¨μ νΉμ ν¨μλ₯Ό λ©λ¦¬μ μ€ννκ² νλλ°, μ΄λ₯Ό μ¬μ©νλ©΄ λμ± νΈλ¦¬νκ² λ°μ΄ν°λ₯Ό μ£Όκ³ λ°μ μ μλ€.
- μ‘μ μ μ²λ¦¬νλ μ½λμ μμ μ μ²λ¦¬νλ μ½λλ₯Ό μΌμΌμ΄ ꡬνν νμκ° μλ€.
- μ‘μμ λ©μμ§ ννκ° λ³κ²½λμμ λ μ‘μ μ΄λ μμ μ μ²λ¦¬νλ μ½λλ₯Ό μμ νλ€κ° μ€μν μνμ΄ μλ€.
RMIλ μλμΌλ‘ λ§λ€μμ΄μΌ νλ μ½λλ₯Ό μλμΌλ‘ λ§λ€μ΄μ€λ€. μ‘μ νλ μͺ½μμλ μ€μ ν¨μ λμ μ‘μ μ λ΄λΉνλ μ½λκ° μ€νλλλ°, μ‘μ μ λ΄λΉνλ μ½λλ 'ν¨μ νΈμΆμ λμ νλ€'λΌλ μλ―Έλ‘ proxyλΌκ³ λ νλ€. λ°λλ‘ μμ νλ μͺ½μμλ λ°λ λ©μμ§λ₯Ό λΆμνμ¬ μ€μ ν¨μλ₯Ό νΈμΆν΄μ€λ€. μμ μ λ΄λΉνλ μ½λλ 'ν¨μλ₯Ό νΈμΆν΄μ£Όλ κΈ°λ°'μ΄λΌλ μλ―Έλ‘ stubλΌκ³ λ νλ€.
class SenderCode
{
// μλμΌλ‘ μμ±λλ μ½λ
Knight_Move(SendTo, position, motion)
{
Message msg;
msg.Write(ID_Knight_Move);
msg.Write(position);
msg.Write(motion);
Send(SendTo, msg);
}
}
class ReceiverCode
{
// μλμΌλ‘ μμ±λλ μ½λ
ProcessReceivedMessage(Message msg)
{
ID = msg.Read();
switch (ID)
{
case ID_Knight_Move:
position = msg.Read();
motion = msg.Read();
Knight_Move(position, motion);
break;
...
}
}
Knight_Move(position, motion)
{
// μ¬κΈ°μ μ½λλ₯Ό μμ±νλ€.
}
}
7. ν΄λΌμ΄μΈνΈλΌλ¦¬ P2P ν΅μ
νλΌμ°λλ·μμλ μλ² μμ΄ ν΄λΌμ΄μΈνΈλΌλ¦¬ ν΅μ νλ κΈ°λ₯μ μ 곡νλ€. μ΄λ₯Ό P2P νΉμ νΌμ΄ν¬νΌμ΄ λ€νΈμνΉμ΄λΌ νλ€.
- μλ²κ° μΉμΈν΄μΌλ§ P2P μ°κ²°μ΄ κ°λ₯νλ€. μλ²μμ ν΄λΌμ΄μΈνΈ 1κ³Ό 2λ₯Ό P2P μ°κ²°νλΌκ³ μ§μνλ©΄, ν΄λΌμ΄μΈνΈ 1κ³Ό 2λ μλ‘κ° P2P μ°κ²°μ΄ λμμμ μ¦μ μ μ μλ€.
- μ΄λλ ν΄λΌμ΄μΈνΈλ€μ λ¬Άμ΄ P2P κ·Έλ£Ήμ΄λΌ λΆλ₯Έλ€. μ΄ ν΄λΌμ΄μΈνΈλΌλ¦¬λ§ P2P λ€νΈμνΉμ ν μ μλ€.
HostID list[2];
list[0] = C1;
list[1] = C2;
// λ λ²μ§Έ μΈμ = λ°°μ΄ ν¬κΈ°
G = s->CreateP2PGroup(list, 2);
8. μ€λ λ λͺ¨λΈ
νλΌμ°λλ·μ μ€λ λ λͺ¨λΈμ λ κ°μ§ ννλ‘ μ 곡νλ€.
- μλ² νλ‘μΈμ€ νλκ° μ€λ λ μ¬λΏ κ°μ§λ ννμ μλ²
- μ¬λ¬μ μ¬λ¬ μλ² νλ‘μΈμ€κ° κ°κ° μ€λ λ νλλ₯Ό κ°μ§λ ννμ μλ²
κΈ°λ³Έκ°μΌλ‘ NetServerμ μ컀 μ€λ λ(worker thread)λ CPU κ°μλ§νΌ ꡬλνλ€. λ€μ λ§ν΄μ CPU κ°μλ§νΌ μ€λ λλ₯Ό κ°μ§ μ€λ λ νμ΄ κΈ°λ³ΈμΌλ‘ μ 곡λλ€.