패킷매니저 수정
class PacketManager
{
#region Singleton
static PacketManager _instance = new PacketManager();
public static PacketManager instance{ get { return _instance; } }
#endregion
PacketManager()
{
Register();
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DummyClient
{
class SessionManager
{
static SessionManager _session = new SessionManager();
public static SessionManager Instace { get { return _session; } }
List<ServerSession> sessions = new List<ServerSession>();
object _lock = new object();
public void SendForEach()
{
foreach(ServerSession session in sessions)
{
C_Chat chatPacket = new C_Chat();
chatPacket.chat = $"Hello Server!";
ArraySegment<byte> segment = chatPacket.Write();
session.Send(segment);
}
}
public ServerSession Generate()
{
lock (_lock)
{
ServerSession session = new ServerSession();
sessions.Add(session);
return session;
}
}
}
}
using DummyClient;
using ServerCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// 패킷이 조립이 다 되었으면 무엇을 호출할까를 기술
class PacketHandler
{
// 어떤 세션에서 조립이 되었는가 / 어떤 패킷인가 받아옴
// 패킷 내부 내용을 출력
// S_ : packet(server to client)
public static void S_ChatHandler(PacketSession session, IPacket packet)
{
S_Chat chatPacket = packet as S_Chat;
ServerSession serverSession = session as ServerSession;
//if(chatPacket.playerId == 1)
Console.WriteLine(chatPacket.chat);
}
}
using ServerCore;
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);
Connector connector = new Connector();
connector.Connect(endPoint,
() => { return SessionManager.Instace.Generate(); },
10);
while (true)
{
try
{
// 모든 클라이언트가 채팅 패킷을 쏘게 만듦
SessionManager.Instace.SendForEach();
}
catch(Exception e)
{
Console.WriteLine(e.ToString());
}
Thread.Sleep(250);
}
}
}
}
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
서버
브로드캐스트 수정
namespace Server
{
class GameRoom
{
List<ClientSession> _sessions = new List<ClientSession>();
object _lock = new object();
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();
// lock 여부는 다른 스레드랑 공유하는 데이터인지 고민해야함
lock (_lock)
{
// 서버가 각 세션에 chat 뿌림
foreach (ClientSession s in _sessions)
{
s.Send(segment);
}
}
}
현재 Session에 OnRecvCompleted()에서 args.ByteTransferred = 0 으로 보내져 Disconnect 되는 오류 있음!!!
-> ServerCore namespace의 Session Class에서 OnReceiveCompleted()시 OnRecv()함수를 통해 데이터를 넘겨주고 얼마만큼 처리 했는지 processLen을 return 받는데 이떄 return 값이 0으로 되어있었음...
return 값을 processLen으로 수정하니 정상작동합니다.
해결과정
계속해서 disconnect가 일어남 -> 모든 disconnect에 breakPoint 걸어서 살펴봄 -> args.BytesTransferred가 0이여서 disconnect가 일어나는 현상을 발견 -> 요리저리 뒤져봐도 send, recv는 잘되는거 같은데 이유를 찾을 수 없었음 -> 만약 출력이 정상적으로 작동한다면 각 client쪽에서 특정 세션에 대한 값이 10번 출력되어야만 함 (한 클라이언트의 채팅을 받고 서버가 그 채팅을 10명의 클라이언트에게 뿌려주므로 로그가 10번 씩 남아야함) -> 그런데 출력이 마구잡이로 찍힘 -> 뭐지 싶어서 클라이언트 수를 1로 줄이고 테스트해봄 -> 또 똑같이 disconnect 발생 -> 한번 recvBuffer크기를 늘려서 실행해봄 -> 1024로 크기를 설정했을 때 보다 좀 더 출력이 오래 유지됨을 발견
-> recvBuffer의 Clear()이 작동을 안해서 그런가? -> recvBuffer의 FreeSize(recvBuffer 남은 공간)을 Clear() 함수에서 로그로 찍어봄 -> Freesize가 점점 감소함!!! -> Clear() 작동은 정상적이니 recvBuffer의 OnRead(), OnWrite() 문제인가? 찾아봄
-> 그러나 정상 작동... -> Recv 부분 함수를 각각 breakpoint 걸어 넘겨서 살펴보면서 값이 잘못 들어가고 있는 곳이 없는지 확인 -> OnReceiveCompleted에서 OnRecv이 0을 return 함을 발견!! -> 분명 데이터를 처리한 양을 리턴해야하는데 왜그러지하고 OnRecv() 함수를 살펴봄 -> OnRecv 함수의 멤버변수인 processLen이 처리한 데이터의 길이를 저장하고 return 해줘야하는데 return 값이 0으로 되어있음을 발견 -> processLen을 return 하도록 하니 정상작동!
사실 어느정도 운빨로 발견함 감이 없잖아 있음...
'C# > 네트워크 관련' 카테고리의 다른 글
복습 Server (0) | 2025.01.05 |
---|---|
복습 Server Core (0) | 2025.01.05 |
채팅 테스트 #1 (1) | 2025.01.01 |
Packet Generator #6 (1) | 2024.12.30 |
Packet Generator #5 (1) | 2024.12.28 |