public void TickClient(float dt, byte[] recvBuffer, ref NetIOMetrics reliableChannelMetrics, ref NetIOMetrics unreliableChannelMetrics) { Perf.Begin("SocketNetDriver.TickClient"); if (_serverConnection != null) { bool wasReset = false; bool isDisposed = false; try { wasReset = _serverConnection.sockets[0].Poll(0, SelectMode.SelectRead); } catch (Exception) { isDisposed = true; } if (isDisposed || (wasReset && (_serverConnection.sockets[0].Available == 0))) { Debug.LogError("Server connection was reset."); _serverConnection.Dispose(); // don't set _serverConnection to null so NetDriverConnection's can be cleaned up correctly. Perf.End(); return; } Recv(_serverConnection, _clientCallbacks, _serverConnection.sockets[0], recvBuffer, ref reliableChannelMetrics, false); if (_serverConnection != null) { Recv(_serverConnection, _clientCallbacks, _serverConnection.sockets[1], recvBuffer, ref unreliableChannelMetrics, true); } if (_serverConnection != null) { if (!_serverConnection.didHandshake && (_serverConnection.channelID != -1)) { _sendUdpControlTimeout -= dt; if (_sendUdpControlTimeout <= 0f) { _sendUdpControlTimeout = UDP_CONTROL_RESEND_TIMEOUT; SendUdpControl(_serverConnection); } } } } Perf.End(); }
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(); }