강의

멘토링

로드맵

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

강감찬님의 프로필 이미지
강감찬

작성한 질문수

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

Connector

강의에 질문이 있습니다

작성

·

37

0

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace ServerParctice
{
    internal class Connector
    {
        Func<Session> _sessionFactory;
        public void Connect(IPEndPoint endPoint, Func<Session> sessionFactory) // 커넥트할건데 비동기로 할거 
        {
            // 일단 연결할 상대방의 주소를 알아야겟지? 
            Socket socket = new Socket(endPoint.AddressFamily,SocketType.Stream,ProtocolType.Tcp);
            SocketAsyncEventArgs connectArgs = new SocketAsyncEventArgs();
            _sessionFactory = sessionFactory;
            connectArgs.Completed += OnConnectCompleted;
            connectArgs.RemoteEndPoint = endPoint;
            connectArgs.UserToken = socket;
            RegisterConnect(connectArgs);
        }

        void RegisterConnect(SocketAsyncEventArgs args)
        {
            Socket socket = args.UserToken as Socket;
            bool pending = socket.ConnectAsync(args);
            if(pending == false)
            {
                OnConnectCompleted(null,args);
            }
        }

        void OnConnectCompleted(object sender, SocketAsyncEventArgs args)
        {
            if(args.SocketError == SocketError.Success)
            {
                Session session = _sessionFactory.Invoke();
                session.Start(args.ConnectSocket);
                session.OnConnect(args.RemoteEndPoint);
            }
            else
            {
                Console.WriteLine($"OnConnectCompleted Failed : {args.SocketError} ");
            }
        }
    }
}

강의 코드인데요, Connector객체는 하나만 만들고 그 Connector가 Connect()를 호출하면서 연결할 서버들의 소켓을 만들고 세션을 만드는데요. Func<Session> sessionFactory; 이 부분이 왜 전역변수로 관리되는지가 궁금해요. Connect()를 호출할때마다 _sessionFactory에 할당되는게 달라지는데 만약 멀티쓰레드 환경에서 동시다발적으로 Connect()를 호출하게 된다고하면 경쟁이 일어날거 같아서요. 만약 Connector객체 하나가 하나의 연결만 관여를 한다면 socket은 왜 전역으로 안 빠져있는지도 궁금하네요

답변 2

0

안녕하세요, 인프런 AI 인턴입니다. 강감찬님, 질문해주신 사항에 대해 설명드리겠습니다.

질문에서 지적하신 부분은 실제 멀티스레드 환경에서 발생할 수 있는 문제를 잘 짚어주셨습니다. 코드상에서 Func<Session> _sessionFactory;가 전역 변수로 관리되면서 발생할 수 있는 문제점은, 멀티스레드 환경에서 여러 스레드가 동시에 Connect()를 호출할 경우 _sessionFactory 변수의 값이 서로 덮어씌워질 가능성이 있다는 점입니다.

전역 변수와 멀티스레드

  • 전역 변수 문제점: Func<Session> _sessionFactoryConnector 클래스의 인스턴스 변수이기에, 여러 스레드에서 동시에 접근 및 수정할 경우 최신 상태를 보장하지 못할 수 있습니다.
  • 해결 방법: 멀티스레드 환경을 고려하는 경우에는 스레드마다 다른 sessionFactory를 갖도록 하기 위해, 별도의 스레드 로컬 변수나, Connect()의 메서드 인자 내부에서만 관리하도록 구성을 조정하는 것이 좋습니다.

소켓과 세션 생성 논리

  • 소켓은 Connect() 내에서 로컬 변수로 선언됩니다. 이는 각 Connect() 호출 시마다 새로운 소켓 인스턴스를 사용하고, 그에 따라 각 연결이 독립적으로 관리되도록 하고자 함입니다.
  • 세션 객체 역시 비슷한 이유로 함수 내부에서 생성하여 각 연결에 독립적으로 작동하도록 합니다.

동시성 제어 방법

멀티 스레드 환경에서는 lock, Monitor, 또는 비동기/병렬 프로그래밍 기술(예: async/await)을 사용하여 데이터 경쟁 문제를 피하는 것이 중요합니다.

관련 질문과 답변들

이와 유사한 주제로 논의된 내용이 있어 참고하시면 도움이 될 것 같습니다.

  1. 펙토리 함수가 꼭 필요한건가요? 그냥 세션으로 받으면 안되요?

    • 세션 팩토리를 사용하는 이유와 멀티스레드 환경 고려 사항에 대해 이해할 수 있습니다.
  2. RemoteEndPoint , UserToken 질문있습니다.

    • Connect()의 내부 로직과 관련된 추가적인 정보가 포함되어 있습니다.

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

0

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

기본적으로 엔진 코드와 컨텐츠 코드는 분리해야 엔진 코드를 재사용할 수 있습니다.
따라서 Func<Session>은 Connection이 맺어질 때 처리하는 함수를 컨텐츠 쪽에서 정의하는 것입니다. 사실 엔진에선 이 기능을 어떻게 활용해 게임을 만들지 예상할 수 없기 때문이죠.

sessionFactory는 말 그대로 처리하는 함수를 연결하는거라,
Connect를 호출할 때마다 sessionFactory를 교체하진 않습니다.
사실 Connect를 멀티쓰레드로 처리할 이유는 없지만
설령 그렇다 하더라도 멀티쓰레드 이슈는 컨텐츠 쪽에서 알아서 처리해야 합니다
(sessionFactory 구현 내부에서 락을 건다거나)

강감찬님의 프로필 이미지
강감찬

작성한 질문수

질문하기