Inflearn brand logo image

인프런 커뮤니티 질문&답변

Rein님의 프로필 이미지
Rein

작성한 질문수

[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버

36. Serialization #3 에서 string (name) 코드 수정 질문

해결된 질문

작성

·

32

0

안녕하세요! 강의 내용은 name을 받는 과정에서 byte[] 직렬화 및 역직렬화 하기 위해 nameLen을 count하고, 이를 ArraySegment에 넣는 과정인데요. 그 과정에서 다음과 같은 코드를 사용합니다.

 

ServerSession.cs 이고, public override ArraySegment<byte> Write()함수 내부입니다.

 

// string
ushort nameLen = (ushort)Encoding.Unicode.GetByteCount(name);

success &= BitConverter.TryWriteBytes(s.Slice(count, s.Length - count), nameLen);

count += sizeof(ushort); // nameLen(2)

Array.Copy(Encoding.Unicode.GetBytes(name), 0, segment.Array, count, nameLen);

count += nameLen; // name(n)

 

여기서 Array.Copy(Encoding.Unicode.GetBytes(name), 0, segment.Array, count, nameLen);

이 부분에서 count 대신 count + segment.Offset 를 사용하는 것이 올바르지 않을까 하여 질문드립니다.

 

이는 for문을 포함하여 코드 실행시 서버 측에서 다음과 같이 나타나기 때문입니다.

Listening...

PlayerInfoReq: playerId=1001, Name=NPC

Received packet: size=20, packetId=1

PlayerInfoReq: playerId=1001, Name=

Received packet: size=20, packetId=1

PlayerInfoReq: playerId=1001, Name=

Received packet: size=20, packetId=1

PlayerInfoReq: playerId=1001, Name=

Received packet: size=20, packetId=1

PlayerInfoReq: playerId=1001, Name=

Received packet: size=20, packetId=1

Client connected: [fe80::9e56:3a99:3a3a:58be%18]:55626

OnDisconnected: [fe80::9e56:3a99:3a3a:58be%18]:55626

 

이처럼, 첫 1회만 NPC라는 네임이 제대로 나타나는 것을 볼 수 있습니다.

 

그러나 count + segment.Offset 를 사용했을 경우는, 다음과 같이 제대로 나타납니다.

 

Listening...

Client connected: [fe80::9e56:3a99:3a3a:58be%18]:55458

PlayerInfoReq: playerId=1001, Name=NPC

Received packet: size=20, packetId=1

PlayerInfoReq: playerId=1001, Name=NPC

Received packet: size=20, packetId=1

PlayerInfoReq: playerId=1001, Name=NPC

Received packet: size=20, packetId=1

PlayerInfoReq: playerId=1001, Name=NPC

Received packet: size=20, packetId=1

PlayerInfoReq: playerId=1001, Name=NPC

Received packet: size=20, packetId=1

OnDisconnected: [fe80::9e56:3a99:3a3a:58be%18]:55458

 

 

물론 이후 리팩토링을 통해 작성한 코드에서는 전부 제대로 나타납니다.

ushort nameLen = (ushort)Encoding.Unicode.GetBytes(this.name, 0, this.name.Length, segment.Array, segment.Offset + count + sizeof(ushort));

(리팩토링 코드)

 

Offset을 사용하지 않을 경우 아마도 패킷을 덮어써서 이런 결과가 나타나는 것 같습니다.

답변 2

1

Rookiss님의 프로필 이미지
Rookiss
지식공유자

네 제 기억으로는 예전에도 한 분이 지적해주신 것 같은데 말씀하신 것이 맞습니다!
해당 부분은 Part7에 protobuf 기반으로 수정이 될 예정입니다.

0

안녕하세요, Rein님. 인프런 AI 인턴입니다.

질문해주신 내용은 패킷 직렬화 중에서 문자열을 제대로 직렬화하지 못해 발생하는 문제점과 그 해결책을 탐구하는 과정 같습니다. 특히, ArraySegment를 이용한 데이터 저장 시 Offset의 사용이 핵심입니다.

요약 및 설명

  1. 문제 발생: Array.Copy()를 사용할 때 count 인덱스 대신 count + segment.Offset를 사용하지 않는 경우, 초기 패킷 이외의 데이터가 저장될 때 덮어씌워지는 문제가 발생합니다. 이것은 데이터가 저장되어야 할 적절한 위치를 지정하지 않았기 때문입니다.

  2. 해결 법: 조정된 코드에서는 count + segment.Offset를 사용하여 데이터가 저장될 위치를 명확히 지정해 줌으로써 모든 패킷에서 문자열이 제대로 직렬화 및 역직렬화 됩니다. 이는 ArraySegment가 메모리의 특정 부분을 나타내기 때문에 Offset을 사용해 주어진 배열의 적절한 시작 지점을 지정해야 함을 보여줍니다.

  3. 리팩토링 개선: 또한, 질문에 언급된 리팩토링 코드에서는 Encoding.Unicode.GetBytessegment.Offset을 포함하여 직접 사용하는 것으로, 초기 2 바이트를 보낸 후 이름 데이터를 바로 처리하는 형태로 개선되었습니다.

관련하여 유사한 주제를 다룬 질문을 참고하시면 도움이 될 수 있습니다:

이 링크들은 문자열 직렬화 및 역직렬화 과정에서 Offset를 포함한 데이터 위치 문제에 대한 이해를 도와줄 것입니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

Rein님의 프로필 이미지
Rein

작성한 질문수

질문하기