Compare commits
2 Commits
d16e4a05e5
...
8f49d3a5b4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f49d3a5b4 | ||
|
|
4ef58c2fad |
@@ -100,12 +100,9 @@ public class DummyClientService
|
||||
{
|
||||
int totalSent = 0, totalRecv = 0;
|
||||
int connected = 0;
|
||||
int rttClientCount = 0;
|
||||
|
||||
Log.Information("───────────── Performance Report ─────────────");
|
||||
|
||||
double totalAvgRtt = 0;
|
||||
|
||||
foreach (DummyClients c in clients)
|
||||
{
|
||||
NetStatistics? stats = c.peer?.Statistics;
|
||||
@@ -113,16 +110,11 @@ public class DummyClientService
|
||||
float lossPct = stats?.PacketLossPercent ?? 0f;
|
||||
|
||||
Log.Information(
|
||||
"[Client {ClientId:00}] Sent={Sent} Recv={Recv} | Loss={Loss}({LossPct:F1}%) AvgRTT={AvgRtt:F3}ms LastRTT={LastRtt:F3}ms",
|
||||
c.clientId, c.SentCount, c.ReceivedCount, loss, lossPct, c.AvgRttMs, c.LastRttMs);
|
||||
"[Client {ClientId:00}] Sent={Sent} Recv={Recv} | Loss={Loss}({LossPct:F1}%)",
|
||||
c.clientId, c.SentCount, c.ReceivedCount, loss, lossPct);
|
||||
|
||||
totalSent += c.SentCount;
|
||||
totalRecv += c.ReceivedCount;
|
||||
if (c.RttCount > 0)
|
||||
{
|
||||
totalAvgRtt += c.AvgRttMs;
|
||||
rttClientCount++;
|
||||
}
|
||||
|
||||
if (c.peer != null)
|
||||
{
|
||||
@@ -130,12 +122,10 @@ public class DummyClientService
|
||||
}
|
||||
}
|
||||
|
||||
double avgRtt = rttClientCount > 0 ? totalAvgRtt / rttClientCount : 0;
|
||||
|
||||
Log.Information("────────────────────────────────────────────");
|
||||
Log.Information(
|
||||
"[TOTAL] Sent={Sent} Recv={Recv} Connected={Connected}/{Total} AvgRTT={AvgRtt:F3}ms",
|
||||
totalSent, totalRecv, connected, clients.Count, avgRtt);
|
||||
"[TOTAL] Sent={Sent} Recv={Recv} Connected={Connected}/{Total}",
|
||||
totalSent, totalRecv, connected, clients.Count);
|
||||
Log.Information("────────────────────────────────────────────");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using ClientTester.Packet;
|
||||
using LiteNetLib;
|
||||
@@ -13,12 +12,7 @@ public class DummyClients
|
||||
private EventBasedNetListener listener;
|
||||
private NetDataWriter? writer;
|
||||
public NetPeer? peer;
|
||||
public long clientId;
|
||||
|
||||
// seq → 송신 타임스탬프 (Stopwatch tick)
|
||||
private ConcurrentDictionary<int, long> pendingPings = new();
|
||||
private int seqNumber;
|
||||
private const int MAX_PENDING_PINGS = 1000;
|
||||
public long clientId; // 일단 이게 hashKey가 됨 => 0 ~ 1000번까지는 더미용응로 뺴둠
|
||||
|
||||
// info
|
||||
private Vector3 position = new Vector3();
|
||||
@@ -28,20 +22,12 @@ public class DummyClients
|
||||
private float preTime = 0.0f;
|
||||
|
||||
// 이동 계산용
|
||||
private static readonly Random random = new();
|
||||
private readonly Stopwatch moveClock = Stopwatch.StartNew();
|
||||
private float posX = 0f;
|
||||
private float posZ = 0f;
|
||||
private float dirX = 0f;
|
||||
private float dirZ = 0f;
|
||||
|
||||
// 유닛 테스트용 (0 = 제한 없음)
|
||||
public int TestCount
|
||||
{
|
||||
get;
|
||||
set;
|
||||
} = 0;
|
||||
|
||||
// 통계
|
||||
public int SentCount
|
||||
{
|
||||
@@ -55,18 +41,6 @@ public class DummyClients
|
||||
get;
|
||||
}
|
||||
|
||||
public double LastRttMs
|
||||
{
|
||||
set;
|
||||
get;
|
||||
}
|
||||
|
||||
public double TotalRttMs
|
||||
{
|
||||
set;
|
||||
get;
|
||||
}
|
||||
|
||||
public int RttCount
|
||||
{
|
||||
set;
|
||||
@@ -86,13 +60,13 @@ public class DummyClients
|
||||
Log.Information("[Client {ClientId:00}] 연결됨", this.clientId);
|
||||
|
||||
// clientID가 토큰의 hashKey라고 가정함
|
||||
PacketHeader packetHeader = new PacketHeader();
|
||||
packetHeader.Code = (PacketCode)1;
|
||||
packetHeader.BodyLength = 4 + sizeof(long);
|
||||
writer.Put(clientId);
|
||||
peer.Send(writer, DeliveryMethod.ReliableOrdered);
|
||||
AccTokenPacket recvTokenPacket = new AccTokenPacket();
|
||||
recvTokenPacket.Token = clientId;
|
||||
|
||||
// 초기화
|
||||
byte[] data = PacketSerializer.Serialize((ushort)PacketCode.ACC_TOKEN, recvTokenPacket);
|
||||
writer.Put(data);
|
||||
peer.Send(writer, DeliveryMethod.ReliableOrdered);
|
||||
writer.Reset();
|
||||
};
|
||||
|
||||
listener.NetworkReceiveEvent += (peer, reader, channel, deliveryMethod) =>
|
||||
@@ -100,25 +74,13 @@ public class DummyClients
|
||||
short code = reader.GetShort();
|
||||
short bodyLength = reader.GetShort();
|
||||
string? msg = reader.GetString();
|
||||
long sentTick;
|
||||
|
||||
if (msg != null && msg.StartsWith("Echo seq:") &&
|
||||
int.TryParse(msg.Substring("Echo seq:".Length), out int seq) &&
|
||||
pendingPings.TryRemove(seq, out sentTick))
|
||||
if (msg != null)
|
||||
{
|
||||
double rttMs = (Stopwatch.GetTimestamp() - sentTick) * 1000.0 / Stopwatch.Frequency;
|
||||
LastRttMs = rttMs;
|
||||
TotalRttMs += rttMs;
|
||||
RttCount++;
|
||||
}
|
||||
|
||||
ReceivedCount++;
|
||||
|
||||
if (TestCount > 0 && ReceivedCount >= TestCount)
|
||||
{
|
||||
peer.Disconnect();
|
||||
}
|
||||
|
||||
reader.Recycle();
|
||||
};
|
||||
|
||||
@@ -143,13 +105,13 @@ public class DummyClients
|
||||
if (distance <= 0f)
|
||||
{
|
||||
// 현재 각도에서 -30~+30도 범위로 회전
|
||||
rotY = (rotY + random.Next(-30, 31) + 360) % 360;
|
||||
rotY = (rotY + Random.Shared.Next(-30, 31) + 360) % 360;
|
||||
float rad = rotY * MathF.PI / 180f;
|
||||
dirX = MathF.Sin(rad);
|
||||
dirZ = MathF.Cos(rad);
|
||||
|
||||
// 3초~12초에 도달할 수 있는 거리 = moveSpeed × 랜덤 초
|
||||
float seconds = 3f + (float)random.NextDouble() * 9f;
|
||||
float seconds = 3f + (float)Random.Shared.NextDouble() * 9f;
|
||||
distance = moveSpeed * seconds;
|
||||
}
|
||||
|
||||
@@ -172,37 +134,27 @@ public class DummyClients
|
||||
}
|
||||
|
||||
UpdateDummy();
|
||||
|
||||
int seq = seqNumber++;
|
||||
pendingPings[seq] = Stopwatch.GetTimestamp();
|
||||
|
||||
// 응답 없는 오래된 ping 정리 (패킷 유실 시 메모리 누수 방지)
|
||||
if (pendingPings.Count > MAX_PENDING_PINGS)
|
||||
TransformPlayerPacket transformPlayerPacket = new TransformPlayerPacket
|
||||
{
|
||||
int cutoff = seq - MAX_PENDING_PINGS;
|
||||
foreach (int key in pendingPings.Keys)
|
||||
PlayerId = (int)clientId,
|
||||
RotY = rotY,
|
||||
Position = new Packet.Vector3
|
||||
{
|
||||
if (key < cutoff)
|
||||
{
|
||||
pendingPings.TryRemove(key, out _);
|
||||
}
|
||||
X = position.X,
|
||||
Y = 0, // 높이는 버린다.
|
||||
Z = position.Z
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
PacketHeader packetHeader = new PacketHeader();
|
||||
packetHeader.Code = 0;
|
||||
packetHeader.BodyLength = (ushort)$"Echo seq:{seq}".Length;
|
||||
writer.Put((short)packetHeader.Code);
|
||||
writer.Put((short)packetHeader.BodyLength);
|
||||
writer.Put($"Echo seq:{seq}");
|
||||
// 순서보장 안함 HOL Blocking 제거
|
||||
peer.Send(writer, DeliveryMethod.ReliableUnordered);
|
||||
// Protobuf 직렬화 + 헤더 조립
|
||||
byte[] data = PacketSerializer.Serialize((ushort)PacketCode.TRANSFORM_PLAYER, transformPlayerPacket);
|
||||
writer.Put(data);
|
||||
// 이동은 손실 감수함
|
||||
peer.Send(writer, DeliveryMethod.Unreliable);
|
||||
SentCount++;
|
||||
writer.Reset();
|
||||
}
|
||||
|
||||
public double AvgRttMs => RttCount > 0 ? TotalRttMs / RttCount : 0.0;
|
||||
|
||||
public void PollEvents()
|
||||
{
|
||||
manager.PollEvents();
|
||||
|
||||
@@ -18,7 +18,7 @@ public class EchoDummyClients
|
||||
// seq → 송신 타임스탬프 (Stopwatch tick)
|
||||
private ConcurrentDictionary<int, long> pendingPings = new();
|
||||
private int seqNumber;
|
||||
private const int MaxPendingPings = 1000;
|
||||
private const int MAX_PENDING_PINGS = 1000;
|
||||
|
||||
// 유닛 테스트용 (0 = 제한 없음)
|
||||
public int TestCount
|
||||
@@ -119,13 +119,15 @@ public class EchoDummyClients
|
||||
pendingPings[seq] = Stopwatch.GetTimestamp();
|
||||
|
||||
// 응답 없는 오래된 ping 정리 (패킷 유실 시 메모리 누수 방지)
|
||||
if (pendingPings.Count > MaxPendingPings)
|
||||
if (pendingPings.Count > MAX_PENDING_PINGS)
|
||||
{
|
||||
int cutoff = seq - MaxPendingPings;
|
||||
int cutoff = seq - MAX_PENDING_PINGS;
|
||||
foreach (int key in pendingPings.Keys)
|
||||
{
|
||||
if (key < cutoff)
|
||||
{
|
||||
pendingPings.TryRemove(key, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -104,12 +104,12 @@ public class PlayerInfo
|
||||
// 인증
|
||||
// ============================================================
|
||||
|
||||
// RECV_TOKEN
|
||||
// ACC_TOKEN
|
||||
[ProtoContract]
|
||||
public class RecvTokenPacket
|
||||
public class AccTokenPacket
|
||||
{
|
||||
[ProtoMember(1)]
|
||||
public string Token
|
||||
public long Token
|
||||
{
|
||||
get;
|
||||
set;
|
||||
|
||||
@@ -3,7 +3,7 @@ namespace ClientTester.Packet;
|
||||
public enum PacketCode : ushort
|
||||
{
|
||||
// 초기 클라이언트 시작시 jwt토큰 받아옴
|
||||
RECV_TOKEN,
|
||||
ACC_TOKEN = 1,
|
||||
|
||||
// 내 정보 로드 (서버 -> 클라)
|
||||
LOAD_GAME,
|
||||
|
||||
Reference in New Issue
Block a user