Version: 2018.2
멀티플레이어 로비(Multiplayer Lobby)
NetworkReader 및 NetworkWriter 시리얼라이저

전송 레이어 API 사용

고수준 네트워킹 API(HLAPI) 외에도 Unity는 전송 레이어라고 불리는 저수준 네트워킹 API도 제공합니다. 전송 레이어를 사용하면 게임 네트워킹에 대한 더욱 구체적이고 세부적인 요구 사항을 충족할 수 있는 고유 네트워킹 시스템을 빌드할 수 있습니다.

전송 레이어는 운영체제의 소켓 기반 네트워킹에서 작동하는 얇은 레이어입니다. 바이트 배열로 표시되는 메시지를 송수신할 수 있으며, 다양한 상황에 적합한 여러 “서비스 품질” 옵션을 제공합니다. 유연성과 성능에 초점이 맞춰져 있고 NetworkTransport 클래스에서 API를 노출시킵니다.

전송 레이어는 네트워크 통신을 위한 기본 서비스를 지원합니다. 기본 서비스는 다음과 같습니다.

  • 연결 구축

  • 다양한 “서비스 품질(QoS)”을 사용한 통신

  • 흐름 제어

  • 기본 통계

  • 릴레이 서버를 통한 통신이나 로컬 검색과 같은 추가 서비스

전송 레이어는 두 개의 프로토콜을 사용할 수 있습니다. UDP 프로토콜은 일반 통신에 사용되고, WebSockets는 WebGL에 사용됩니다. 전송 레이어를 직접 사용하는 일반적인 워크플로는 다음과 같습니다.

  1. 네트워크 전송 레이어 초기화

  2. 네트워크 토폴로지 구성

  3. 호스트 생성

  4. 통신 시작(연결 처리 및 메시지 송수신)

  5. 라이브러리 사용 후 종료

각 섹션에 대한 기술적 세부 사항은 아래의 해당 섹션을 참조하십시오. 각 섹션에는 네트워킹 스크립트에 포함할 수 있는 코드 스니핏이 포함되어 있습니다.

1단계: 네트워크 전송 레이어 초기화

네트워크 전송 레이어를 초기화하는 경우 아래 코드 샘플에서와 같이 인수가 없는 기본 초기화를 선택하거나 최대 패킷 크기와 스레드 타임아웃 제한 등 네트워크 레이어의 전반적인 동작을 제어하는 파라미터를 제공할 수 있습니다.

전송 레이어를 기본 설정으로 초기화하려면 Init()를 호출합니다.


    // Initializing the Transport Layer with no arguments (default settings)
        NetworkTransport.Init();

    To initialize the transport layer with your own configuration just add your configuration as a parameter to Init, as shown below.

        // An example of initializing the Transport Layer with custom settings
        GlobalConfig gConfig = new GlobalConfig();
        gConfig.MaxPacketSize = 500;
        NetworkTransport.Init(gConfig);

네트워킹 환경이 일반적이지 않으며 필요한 특정 설정에 익숙한 경우에만 커스텀 Init 값을 사용해야 합니다. 일반적으로 인터넷에서 플레이하는 통상적인 멀티플레이어 게임을 개발할 때는 기본 Init 설정으로도 충분합니다.

2단계: 네트워크 토폴로지 구성

다음 단계에는 피어 간 연결을 설정합니다. Network topology defines how many connections allowed and what connection configuration will used. If your game needs to send network messages which vary in importance (eg low importance such as incidental sound effects, vs high importance such as whether a player scored a point), 보내려는 메시지 타입이나 게임 안에서의 상대적인 중요성에 따라 통신 채널의 서비스 품질을 다르게 정의하고 싶을 수 있습니다.


    ConnectionConfig config = new ConnectionConfig();
        int myReliableChannelId  = config.AddChannel(QosType.Reliable);
        int myUnreliableChannelId = config.AddChannel(QosType.Unreliable);

위 예제에서는 서비스 품질 값이 서로 다른 통신 채널이 두 개 정의되어 있습니다. QosType.Reliable은 메시지를 전송하고 메시지가 제대로 전달되는지 보장하는 한편, QosType.Unreliable은 메시지를 더 빨리 전송하지만 메시지가 제대로 전달되었는지 확인하지 않습니다.

ConnectionConfig의 프로퍼티를 조절하여 각 연결별로 설정을 지정할 수 있습니다. 하지만 클라이언트를 서로 연결하는 경우 두 연결된 피어의 설정이 동일해야 하며, 그렇지 않으면 CRCMismatch 오류가 발생하여 연결에 실패합니다.

네트워크 설정의 마지막 단계는 토폴로지 정의입니다.


HostTopology topology = new HostTopology(config, 10);

이 예제에서는 호스트 토폴로지가 최대 10개의 연결을 허용할 수 있다고 정의합니다. 이 연결은 1단계에서 설정된 것입니다.

3단계: 호스트 생성

앞의 두 사전 설정 단계를 완료했으면 호스트(오픈 소켓)를 생성해야 합니다.


int hostId = NetworkTransport.AddHost(topology, 8888);

이 코드 예제는 포트 8888과 모든 IP 주소에 새 호스트를 추가합니다. 이 호스트는 최대 10개의 연결을 지원합니다(2단계에서 설정됨). 이 연결은 1단계에서 설정된 것입니다.

4단계: 통신 시작

통신을 시작하려면 또 다른 호스트에 대한 연결을 설정해야 합니다. 이를 위해 Connect()를 호출하십시오. 그러면 사용자와 원격 호스트 간에 연결이 설정됩니다. 연결 성공 여부를 표시하는 이벤트가 수신됩니다.

우선 포트 8888을 사용하여 192.168.1.42에 있는 원격 호스트에 연결하십시오. 할당된 connectionId가 반환됩니다.


connectionId = NetworkTransport.Connect(hostId, "192.168.1.42", 8888, 0, out error);

연결이 구축되면 ConnectEvent가 수신됩니다. 이제 데이터를 전송할 수 있습니다.


NetworkTransport.Send(hostId, connectionId, myReliableChannelId, buffer, bufferLength,  out error);

연결 작업이 끝나면 Disconnect()를 호출하여 호스트 연결을 해제하십시오.

NetworkTransport.Disconnect(hostId, connectionId, out error);

함수 호출에 성공했는지 확인하기 위해 out errorNetworkError에 캐스트할 수 있습니다. NetworkEror.Ok는 오류가 발생하지 않았음을 나타냅니다.

호스트 상태를 점검하려면 아래 두 개의 함수를 사용해야 합니다.

내부 이벤트 대기열에서 이벤트를 폴링하는 경우 다음 중 하나를 호출할 수 있습니다.

NetworkTransport.Receive(out recHostId, out connectionId, out channelId, recBuffer, bufferSize, out dataSize, out error);

또는 NetworkTransport.ReceiveFromHost(recHostId, out connectionId, out channelId, recBuffer, bufferSize, out dataSize, out error);

이 두 함수 모두 대기열의 이벤트를 반환합니다. 첫 번째 함수는 모든 호스트의 이벤트를 반환하고 recHostId 변수에 메시지 출처의 호스트 ID가 할당됩니다. 반면에 두 번째 함수는 제공하는 recHostId에서 지정된 호스트의 이벤트만 반환합니다.

Receive에서 데이터를 폴링하는 한 가지 방법은 Update 함수에서 호출하는 것입니다.


void Update()
{

    int recHostId; 
    int connectionId; 
    int channelId; 
    byte[] recBuffer = new byte[1024]; 
    int bufferSize = 1024;
    int dataSize;
    byte error;
    NetworkEventType recData = NetworkTransport.Receive(out recHostId, out connectionId, out channelId, recBuffer, bufferSize, out dataSize, out error);
    switch (recData)
    {
        case NetworkEventType.Nothing:                     break;
        case NetworkEventType.ConnectEvent:                break;
        case NetworkEventType.DataEvent:                   break;
        case NetworkEventType.DisconnectEvent:            break;

  case NetworkEventType.BroadcastEvent:

       break;
    }
}

다음과 같은 5가지 타입의 이벤트를 수신할 수 있습니다.


case NetworkEventType.ConnectEvent: 
    if(myConnectionId == connectionId)
        //my connect request was approved
    else
        //somebody else sent a connect request to me
    break;

  • NetworkEventType.DataEvent: 데이터 이벤트를 수신했습니다. 수신할 준비가 된 데이터가 있는 경우 데이터 이벤트를 수신합니다. recBuffer가 데이터를 담을 만큼 충분히 큰 경우 데이터는 버퍼에 복사됩니다. 그렇지 않다면 이벤트에 MessageToLong 네트워크 오류가 포함됩니다. 이 경우 버퍼를 더 큰 크기로 재할당하고 DataEvent 함수를 다시 호출해야 합니다.

  • NetworkEventType.DisconnectEvent: 구축된 연결이 해제되었거나, 연결 요청에 실패했습니다. 오류 코드를 확인하여 발생 원인을 찾으십시오.


case NetworkEventType. DisconnectEvent: 
    if(myConnectionId == connectionId)
        //cannot connect for some reason, see error
    else
        //one of the established connections has disconnected
    break;

WebGL 지원

WebGL에 WebSocket을 사용할 수 있습니다. 하지만 웹 클라이언트는 호스트에만 연결되며 직접 호스트 역할을 수행할 수는 없습니다. 다시 말해, 호스트는 스탠드얼론 플레이어(Windows, Mac 또는 Linux 전용)여야 합니다. 클라이언트 측 구성의 경우 위에서 설명한 모든 단계(토폴로지 및 설정 포함)가 동일하게 적용됩니다. 서버에서 다음을 호출하십시오.


NetworkTransport.AddWebsocketHost(topology, port, ip);

위 IP 주소는 수신 대기할 특정 주소여야 합니다. 그렇지 않으면 호스트가 모든 네트워크 인터페이스를 수신하도록 만들 때 IP 주소로 null이 전달됩니다.

서버는 한 번에 하나의 WebSocket만 지원할 수 있지만, 동시에 다른 일반 호스트를 처리할 수도 있습니다.


NetworkTransport.AddWebsocketHost(topology, 8887, null);
NetworkTransport.AddHost(topology, 8888);

멀티플레이어 로비(Multiplayer Lobby)
NetworkReader 및 NetworkWriter 시리얼라이저