void Recv(SocketNetDriverConnection connection, INetDriverCallbacks callbacks, Socket socket, byte[] buffer, ref NetIOMetrics metrics, bool isDatagram)
    {
        Perf.Begin("SocketNetDriver.Recv");

        if (isDatagram)
        {
            while (connection.isValid && (socket.Available > 0))
            {
                int r;
                try {
                    r = socket.Receive(buffer, 0, World.MAX_UNRELIABLE_MESSAGE_SIZE, SocketFlags.None);
                    if (r <= 0)
                    {
                        throw new SocketException((int)SocketError.SocketError);
                    }
                    metrics.bytesRecv += r;
                    ++metrics.numPacketsRecv;
                } catch (Exception e) {
                    Debug.LogException(e);
                    callbacks.OnInvalidMessageReceived(connection);
                    continue;
                }

                if (!connection.didHandshake)
                {
                    // client may receive a UDP packet before receiving control ACK
                    // so discard the packet until we process the ACK.
                    continue;
                }

                callbacks.OnMessageReceived(connection, buffer, r);
            }
        }
        else
        {
            while (connection.isValid && (socket.Available > 0))
            {
                if (connection.pendingRecvSize <= 0)
                {
                    if (socket.Available < 2)
                    {
                        break;
                    }

                    // read from socket.
                    if (socket.Receive(connection.pendingBytes, 0, 2, SocketFlags.None) != 2)
                    {
                        throw new SocketException((int)SocketError.SocketError);
                    }

                    connection.pendingRecvSize      = ((int)connection.pendingBytes[0]) | (((int)connection.pendingBytes[1]) << 8);
                    connection.pendingBytesReceived = 0;

                    if (connection.pendingRecvSize > connection.pendingBytes.Length)
                    {
                        callbacks.OnInvalidMessageReceived(connection);
                        continue;
                    }
                }

                {
                    // read from socket.
                    var numBytesToRead = Mathf.Min(socket.Available, connection.pendingRecvSize - connection.pendingBytesReceived);
                    if (numBytesToRead > 0)
                    {
                        if (socket.Receive(connection.pendingBytes, connection.pendingBytesReceived, numBytesToRead, SocketFlags.None) != numBytesToRead)
                        {
                            throw new SocketException((int)SocketError.SocketError);
                        }
                        connection.pendingBytesReceived += numBytesToRead;
                    }
                }

                Assert.IsTrue(connection.pendingBytesReceived <= connection.pendingRecvSize);

                if (connection.pendingBytesReceived >= connection.pendingRecvSize)
                {
                    if (!connection.didHandshake)
                    {
                        if (callbacks == _clientCallbacks)
                        {
                            if (connection.channelID == -1)
                            {
                                var id = RecvControl(connection.pendingBytes, connection.pendingRecvSize);
                                if (id == -1)
                                {
                                    connection.Dispose();
                                    break;
                                }
                                connection.channelID   = id;
                                _sendUdpControlTimeout = UDP_CONTROL_RESEND_TIMEOUT;
                                SendUdpControl(connection);
                            }
                            else if (connection.pendingBytes[0] == (byte)EControlCode.AckChannelID)
                            {
                                connection.didHandshake = true;
                                callbacks.OnConnect(connection);
                            }
                            else
                            {
                                // invalid response
                                connection.Dispose();
                                break;
                            }
                        }
                        else
                        {
                            connection.Dispose();
                            break;
                        }

                        connection.pendingRecvSize      = 0;
                        connection.pendingBytesReceived = 0;
                        continue;
                    }

                    Array.Copy(connection.pendingBytes, buffer, connection.pendingRecvSize);

                    var r = connection.pendingRecvSize;

                    connection.pendingBytesReceived = 0;
                    connection.pendingRecvSize      = 0;

                    metrics.bytesRecv += r;
                    ++metrics.numPacketsRecv;

                    callbacks.OnMessageReceived(connection, buffer, r);
                    continue;
                }

                // not enough data ready
                break;
            }
        }

        Perf.End();
    }
예제 #2
0
    void TickSocket(IntHashtable <UnityNetDriverConnection> connections, INetDriverCallbacks callbacks, int socketID, int reliableChannelID, int unreliableChannelID, byte[] recvBuffer, ref NetIOMetrics reliableChannelMetrics, ref NetIOMetrics unreliableChannelMetrics)
    {
        int  connectionID;
        int  recvSize;
        int  channelID;
        byte error;

        while (true)
        {
            NetworkEventType eventType = NetworkTransport.ReceiveFromHost(socketID, out connectionID, out channelID, recvBuffer, recvBuffer.Length, out recvSize, out error);
            switch (eventType)
            {
            case NetworkEventType.ConnectEvent: {
                var conn = GetConnection(connections, connectionID);
                if (conn == null)
                {
                    conn = CreateConnection(connections, callbacks, socketID, connectionID, reliableChannelID, unreliableChannelID);
                }
                callbacks.OnConnect(conn);
            } break;

            case NetworkEventType.DisconnectEvent: {
                var conn = GetConnection(connections, connectionID);
                if (conn == null)
                {
                    conn = CreateConnection(connections, callbacks, socketID, connectionID, reliableChannelID, unreliableChannelID);
                }
                conn.callbacks = null;
                callbacks.OnDisconnect(conn);
                RemoveConnection(connections, connectionID);
            } break;

            case NetworkEventType.DataEvent: {
                var conn = GetConnection(connections, connectionID);
                if (conn != null)
                {
                    if (channelID == reliableChannelID)
                    {
                        reliableChannelMetrics.bytesRecv += recvSize;
                        ++reliableChannelMetrics.numPacketsRecv;
                    }
                    else
                    {
                        unreliableChannelMetrics.bytesRecv += recvSize;
                        ++unreliableChannelMetrics.numPacketsRecv;
                    }
                    if (error == (byte)NetworkError.MessageToLong)
                    {
                        callbacks.OnInvalidMessageReceived(conn);
                    }
                    else
                    {
                        callbacks.OnMessageReceived(conn, recvBuffer, recvSize);
                    }
                }
            } break;

            default:
                return;
            }
        }
    }
    void RecvFrom(INetDriverCallbacks callbacks, Socket socket, byte[] buffer, ref NetIOMetrics metrics)
    {
        Perf.Begin("SocketNetDriver.RecvFrom");

        while (socket.Available > 0)
        {
            int r;

            try {
                r = socket.ReceiveFrom(buffer, 0, World.MAX_UNRELIABLE_MESSAGE_SIZE, SocketFlags.None, ref _recvEndPoint);
            } catch (Exception e) {
                Debug.LogException(e);

                SocketNetDriverConnection conn;
                if (_udpConnections.TryGetValue(_recvEndPoint, out conn))
                {
                    callbacks.OnInvalidMessageReceived(conn);
                }

                continue;
            }

            if (r <= 0)
            {
                throw new SocketException((int)SocketError.SocketError);
            }

            metrics.bytesRecv += r;
            ++metrics.numPacketsRecv;

            SocketNetDriverConnection connection;
            if (_udpConnections.TryGetValue(_recvEndPoint, out connection))
            {
                if (connection.isValid)
                {
                    if (r > 3)
                    {
                        // currently NetMsgs are always more than 3 bytes, and this guarantees that we don't
                        // try to process a duplicated control udp control message.

                        callbacks.OnMessageReceived(connection, buffer, r);
                    }
                }
            }
            else
            {
                // is this a control code?
                var id = RecvControl(buffer, r);
                if (id != -1)
                {
                    for (int i = 0; i < _tcpConnections.Values.Count; ++i)
                    {
                        var c = _tcpConnections.Values[i];
                        if (c.channelID == id)
                        {
                            if (_udpConnections.Values.Contains(c))
                            {
                                Debug.LogWarning("UDP control message received for registered channel.");
                            }
                            else
                            {
                                c.udpEndpoint = new IPEndPoint(((IPEndPoint)_recvEndPoint).Address, ((IPEndPoint)_recvEndPoint).Port);
                                _udpConnections.Add(c.udpEndpoint, c);
                                SendTcpControlAck(c);
                                c.didHandshake = true;
                                callbacks.OnConnect(c);
                                break;
                            }
                        }
                    }
                }
            }
        }

        Perf.End();
    }