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

GGolDDuKi님의 프로필 이미지

작성한 질문수

[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part7: MMO 컨텐츠 구현 (Unity + C# 서버 연동 기초)

마무리

홀펀칭 질문도 괜찮을까요..?

24.04.26 14:22 작성

·

255

·

수정됨

0

안녕하세요, 루키스님

유익한 강의 제공해주셔서 감사합니다
항상 감사한 마음으로 수강하고 열심히 프로젝트를 진행해보고 있습니다.

현재 프로젝트에서

  1. 메인 서버에서는 모든 클라 게임 접속을 받고 로그인 및 방 입장 등을 관리합니다.

  2. 클라가 게임룸을 생성하면 해당 클라에 Host라는 오브젝트가 생성되고, 해당 오브젝트는 서버 코드를 유니티에 호환되도록 수정을 거친 상황입니다.

  3. 타 클라(로컬 네트워크 환경에서만 테스트 해보았습니다.)에서 방 목록에서 방을 선택하고 입장하면 중앙 서버에서가 호스트와 클라 사이에서 IP와 포트를 알려주는 중개 역할을 하며 두 클라이언트가 연결됩니다.

  4. 해당 게임의 사이클이 끝나 게임이 종료되면, 클라이언트들은 로비로 돌아가며 1~3의 단계가 계속해서 반복됩니다.

현재 프로젝트의 조건을 위와 같이 설정하였고,
3번까지는 테스트를 완료했고, 정상적으로 동작하는 것을 확인했습니다.

 

하지만 4번에서 문제가 발생하는데,

다시 방을 생성하면 클라와 호스트 사이에 패킷 전송이 되지 않는 것 같습니다.

디버깅을 통해 확인해볼 때에는 호스트측의 OnConnected 메서드는 호출되는 것으로 보아서는 클라측에서 연결에 문제가 발생하는 것 같은데,

구글링과 디버깅을 통해 여러가지 해결책을 시행해봤습니다.

  1. 연결 종료 시 완전히 소켓이 종료되도록 세션 Disconnect()를 했습니다.

  2. 소켓이 같은 주소의 포트 번호를 공유할 수 있도록 Connector와 Listener 코드의 소켓 설정 코드에

Socket socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);

이렇게 ReuseAddress 설정을 추가했습니다.

  1. (중앙 서버 세션과 호스트 세션은 클라에서 개별적으로 다루고 있습니다)호스트 세션의 연결이 종료될 때, 호스트 세션의 _disconnected 변수를 다시 0으로 만들어,
    다음 연결 시 RegisterRecv등의 코드에서 if(_disconnected == 1) return;의 조건문에 걸리지 않도록 코드를 수정해보았습니다.

2번의 방법을 시행해보기 전에는 '같은 주소의 포트를 사용할 수 없습니다?'와 같은 오류가 발생했었는데,
2번을 시행한 뒤에는 오류는 발생하지 않지만 연결이 되지 않는 것은 마찬가지인 상태입니다.

그 외에도 잡다하게 정말 많은 시도를 해보았는데,
전혀 실마리가 보이지 않아 질문합니다..ㅠㅠ

답변 2

0

kmg013329님의 프로필 이미지

2024. 06. 26. 18:58

안녕하세요.

같은 문제를 겪고 있어서 그런데 혹시 해결하셨나요?

0

인프런 AI 인턴님의 프로필 이미지

2024. 04. 28. 14:26

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

GGolDDuKi님의 프로젝트에 대한 질문을 잘 읽었습니다. 홀펀칭 문제는 네트워킹에서 까다로운 문제 중 하나이며, 특히 유니티와 같은 게임 엔진에서는 더욱 주의 깊게 다루어야 하는 주제입니다. GGolDDuKi님께서 시도하신 방법들은 모두 유효한 접근 방식이지만, 문제가 해결되지 않은 것으로 보입니다. 문제 해결을 위해 몇 가지 추가적인 제안을 드리고자 합니다.

  1. NAT Traversal 기술 적용 고려: 홀펀칭 기술 외에도 NAT Traversal을 위한 다양한 기술이 있습니다. UPnP(Universal Plug and Play)나 STUN(Session Traversal Utilities for NAT), TURN(Traversal Using Relays around NAT) 같은 기술을 검토해 보시기 바랍니다. 이런 기술들은 클라이언트 간의 직접적인 연결을 용이하게 만들어줄 수 있습니다.

  2. 포트 재사용 관련 문제 재점검: ReuseAddress 소켓 옵션을 사용하시는 점은 좋은 접근입니다. 하지만, 연결이 종료된 후에도 항상 소켓이 즉시 재사용 가능한 상태가 되는 것은 아닙니다. 특히 UDP 홀펀칭 시도시에는 SO_REUSEADDR 또는 SO_REUSEPORT (플랫폼에 따라 다름) 소켓 옵션 설정이 필요할 수 있습니다. 플랫폼별로 상이한 동작을 확인해 보시기 바랍니다.

  3. 타임아웃과 재시도 로직 추가 고려: 연결 시도 후 연결이 성립하지 않는 경우, 일정 시간 후 재시도하는 로직을 구현해 보세요. 네트워크 상태가 일시적으로 불안정할 수 있으므로, 몇 번의 재시도 후에 연결이 성립할 수 있습니다.

  4. 로그 및 네트워크 패킷 분석: Wireshark와 같은 네트워크 패킷 분석 도구를 이용하여, 실제로 패킷이 송수신되는지, 예상한 대로 통신이 이루어지는지 확인해보시기 바랍니다. 백엔드와 클라이언트 간의 통신 과정에서 어느 지점에서 문제가 발생하는지 좀 더 명확히 파악할 수 있습니다.

네트워크 관련 문제는 경우의 수가 매우 다양하므로, 문제의 원인을 정확히 파악하기 위해서는 다양한 시행착오와 테스트가 필요합니다. GGolDDuKi님께서는 이미 많은 노력을 하고 계신 것으로 보이며, 조금 더 다양한 방법을 시도해 보시면 문제를 해결하실 수 있을 것이라 기대됩니다.