Host Migration (Migración de anfitrión)
Servicios de Internet

Utilizando el API del Transport Layer

Adicionalmente al API de Alto Nivel de networking que proporcionamos - lo cual proporciona sistemas fácil de utilizar para manejar jugadores, GameObjects en red, y otros requerimientos comunes - nosotros también damos acceso a un API de más bajo nivel llamado “Transport Layer”. Esto le proporciona a usted la habilidad de bajo nivel, la cual puede ser útil si usted tiene requerimientos más específicos o avanzados para el networking de su juego.

El Transport Layer está dentro de una capa delgada que funciona encima del networking (red) del sistema operativo basado en sockets. Es capaz de enviar y recibir mensajes representados como arreglos de bytes, y ofrece una cantidad de diferentes opciones “quality of service” (calidad de servicio) para diferentes escenarios. Se enfoca en flexibilidad y rendimiento, y expone un API dentro de la clase UnityEngine.Networking.NetworkTransport.

La Transport Layer soporte servicios bases para la comunicación en red. Estos servicios base incluye:

  • Establecer conexiones
  • Comunicándose utilizando una variedad de “quality of services” (calidad de servicios)
  • Flujo de control
  • Estadísticas base
  • Servicios adicionales como comunicarse vía un relay server o local discovery

El Transport Layer puede utilizar dos protocolos: UDP para comunicaciones genéricas, y WebSockets para WebGL. Para utilizar el Transport Layer directamente, el flujo de trabajo típico sería como el que sigue:

  1. Inicialize el Network Transport Layer
  2. Configure la topología de la red
  3. Cree un anfitrión
  4. Empiece la comunicación (manejar conexiones y enviar/recibir mensajes)
  5. Apague la librería después de su uso.

Inicializando el Network Transport Layer

Cuando inicialice el Network Transport Layer, usted puede escoger entre la inicialización predeterminado, sin argumentos, o usted puede proporcionar parámetros que controlan el comportamiento general de la capa en red, tal como el maximum packet size (tamaño máximo del paquete) y thread timeout limit (tiempo limite del thread).

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

En el segundo ejemplo arriba, el Transport Layer está inicializado con un valor personalizado “MaxPacketSize” especificado a 500. Los valores personalizados Init deberían solamente ser utilizados si usted tiene un ambiente inusual de networking y son familiares con los ajustes específicos que usted necesita. Como regla, si usted está desarrollando un juego multi-jugador típico diseñado a ser jugado a través del internet, los ajustes Init() predeterminados sin argumentos deberían ser apropiados.

Configuración

El siguiente paso es configurar una conexión entre los compañeros. Usted podría definir varios canales de comunicación, cada uno con un nivel de quality of service diferente especificado para que encaje con los típicos específicos de mensajes que usted quiere enviar, y su importancia relativa dentro de su juego.

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

En el ejemplo de arriba, nosotros definimos dos canales de comunicación con diferentes valores de quality of service. “QosType.Reliable” enviará un mensaje y se asegurará que el mensaje es enviado, mientras que “QosType.Unreliable” enviará un mensaje sin asegurarse, pero lo hará más rápido.

También es posible especificar unos ajustes de configuración específicamente para cada conexión, al ajustes propiedades en el objeto ConnectionConfig. Sin embargo, cuando haga una conexión de un cliente a otro, los ajustes deberían ser los mismo para ambos compañeros conectados o la conexión fallará con un error CRCMismatch.

Topología

El paso final de la configuración en red es la definición de topología. La topología en red define qué tantas conexiones son permitidas y qué configuración en red será utilizada.

HostTopology topology = new HostTopology(config, 10);

Aquí hemos creado una topología que permite hasta 10 conexiones, cada uno será configurada con parámetros definidos en un paso previo.

Creación de un anfitrión

Como todos los pasos preliminares se han hecho, podemos crear un anfitrión (socket abierto):

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

Aquí hemos agregado un nuevo anfitrión en el puerto 8888 y cualquier dirección ip. Este anfitrión soportará hasta 10 conexiones, y cada conexión tendrá parámetros que hemos definido en el objeto config.

Comunicación

Como anfitrión que hemos creado, nosotros podemos empezar nuestra comunicación. Para hacer esto, enviamos diferentes comandos al anfitrión y revisamos su estatus. Hay 3 comandos principales que podemos enviar:

connectionId = NetworkTransport.Connect(hostId, "192.16.7.21", 8888, 0, out error);
NetworkTransport.Disconnect(hostId, connectionId, out error);
NetworkTransport.Send(hostId, connectionId, myReiliableChannelId, buffer, bufferLength,  out error);
  1. El primer comando enviará una solicitud de conexión al compañero con ip “192.16.7.21” y puerto 8888. Este devolverá el id asignado a esta conexión.
  2. El segundo enviará una solicitud de desconexión,
  3. Y tercero enviará un mensaje, a la conexión con un id igual a connectionId, utilizando un canal de confianza con id igual a myReiliableChannelId, un mensaje se debería almacenar en el buffer[] y la longitud del mensaje debería estar definida por bufferLength.

Para revisar el estado del anfitrión usted puede utilizar dos funciones:

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);

Ambos devuelven eventos, la primera función devolverá eventos de cualquier anfitrión (y devolverá un id de anfitrión via recHostId) el segundo formulario comprobará el anfitrión con id recHostId. Usted puede utilizar cualquier de estas funciones dentro del método 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:         //1
            break;
        case NetworkEventType.ConnectEvent:    //2
            break;
        case NetworkEventType.DataEvent:       //3
            break;
        case NetworkEventType.DisconnectEvent: //4
            break;
    }
}
  • Punto 1: Ningún evento interesante se ha devuelto.
  • Punto 2: Un evento de conexión llega. Puede ser una nueva conexión, o puede ser una respuesta a un comando de conexión previo:
myConnectionId = NetworkTransport.Connect(hostId, "192.16.7.21", 8888, 0, out error);
NetworkEventType recData = NetworkTransport.Receive(out recHostId, out connectionId, out channelId, recBuffer, bufferSize, out dataSize, out error);
switch (recData)
{
    case NetworkEventType.ConnectEvent: 
        if(myConnectionId == connectionId)
            //my active connect request approved
        else
            //somebody else connect to me
        break;
    //...   
}
  • Punto 3: Datos recibidos. En este caso recHostId definirá el anfitrión, connectionId definirá la conexión, channelId definirá el canal; dataSize definirá el tamaño de los datos recibidos. Si recBuffer es suficientemente grande para contener datos, los datos serán copiados en el buffer. Si no, error contendrá un mensaje de error MessageToLong y usted necesitará re-asignar su buffer y llamar esta función nuevamente.
  • Punto 4: Una señal de desconexión entra. Puede ser una señal diciendo que la conexión establecida se ha desconectado o que su solicitud de conexión ha fallado.
myConnectionId = NetworkTransport.Connect(hostId, "192.16.7.21", 8888, 0, out error);
NetworkEventType recData = NetworkTransport.Receive(out recHostId, out connectionId, out channelId, recBuffer, bufferSize, out dataSize, out error);
switch (recData)
{
    case NetworkEventType. DisconnectEvent: 
        if(myConnectionId == connectionId)
            //cannot connect by some reason see error
        else
            //one of the established connection has been disconnected
        break;
    \\...   
}

Soporte WebGL

El WebSocket en el cliente ha sido soportado. Para el lado del cliente, todos los pasos descritos arriba (incluyendo la topología y configuración) deberían ser los mismos. Los clientes web se pueden conectar al servidor solamente, dónde el servidor es un standalone player (Win, Mac, o Linux solamente). En el servidor usted debería llamar

NetworkTransport.AddWebsocketHost(topology, port, ip);

Dónde la dirección ip es la dirección que escucha, usted puede pasar null como la dirección ip en este caso el anfitrión escuchara todas las interfaces de network (red). El servidor puede soportar solamente un Websocket Host y al mismo tiempo, puede manejar anfitriones genéricos también:

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

Abrirá un socket tcp que maneja un protocolo socket web en puerto 8887 y un socket udp manejando un protocol genérico en puerto 8888.

Host Migration (Migración de anfitrión)
Servicios de Internet