private IEnumerator Run() { // Reconnection attempts so we don't hammer the system on failure. float connectionPollTimeSec = 0.25f; TcpClient socket = null; PacketBuffer packetBuffer = new PacketBuffer(4 * 1024); System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch(); ClientConnector connector = null; while (!_quitFlag) { // First try establish a connection. while (!_quitFlag && !_connection.Connected) { if (connector == null) { connector = new ClientConnector(_connection.EndPoint); } if (!connector.Connecting) { if (connector.Connected) { socket = connector.Accept(); connector = null; _connection.Connected = true; Status = NetworkThreadStatus.Connected; _currentFrame = _totalFrames = 0u; _packetQueue.Enqueue(BuildResetPacket()); } else { connector.Abort(); connector = null; if (!_connection.AutoReconnect) { // Failed connection and no auto reconnect. Status = NetworkThreadStatus.ConnectionFailed; break; } } } if (socket == null) { // Wait the timeout period before attempting to reconnect. yield return(Workthread.CreateWait(connectionPollTimeSec)); } } timer.Start(); // Read while connected. while (!_quitFlag && TcpClientUtil.Connected(socket)) { // We have a connection. Read messages while we can. if (socket.Available > 0) { // Data available. Read from the network stream into a buffer and attempt to // read a valid message. packetBuffer.Append(socket.GetStream(), socket.Available); PacketBuffer completedPacket; bool crcOk = true; while ((completedPacket = packetBuffer.PopPacket(out crcOk)) != null || !crcOk) { if (crcOk) { // Decode and decompress collated packets. This will just return the same packet // if not collated. _collatedDecoder.SetPacket(completedPacket); while ((completedPacket = _collatedDecoder.Next()) != null) { if (completedPacket.Header.RoutingID == (ushort)RoutingID.Control) { ushort controlMessageId = completedPacket.Header.MessageID; if (controlMessageId == (ushort)ControlMessageID.EndFrame) { timer.Stop(); FrameTime = timer.ElapsedMilliseconds * 1e-3f; timer.Reset(); timer.Start(); ++_currentFrame; ++_totalFrames; } } _packetQueue.Enqueue(completedPacket); } } else { // TODO: Log CRC failure. } } } else { yield return(null); } } // Disconnected. if (socket != null) { socket.LingerState.Enabled = false; socket.Close(); socket = null; } if (_connection.Connected) { Status = NetworkThreadStatus.Disconnected; _connection.Connected = false; } if (!_connection.AutoReconnect) { break; } Status = NetworkThreadStatus.Reconnecting; } }
private IEnumerator Run() { // Reconnection attempts so we don't hammer the system on failure. float connectionPollTimeSec = 0.25f; TcpClient socket = null; PacketBuffer packetBuffer = new PacketBuffer(4 * 1024); System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch(); ClientConnector connector = null; while (!_quitFlag) { // First try establish a connection. while (!_quitFlag && !_connection.Connected) { if (connector == null) { connector = new ClientConnector(_connection.EndPoint); } if (!connector.Connecting) { if (connector.Connected) { socket = connector.Accept(); connector = null; _connection.Connected = true; Status = NetworkThreadStatus.Connected; _currentFrame = _totalFrames = 0u; _packetQueue.Enqueue(BuildResetPacket()); } else { connector.Abort(); connector = null; if (!_connection.AutoReconnect) { // Failed connection and no auto reconnect. Status = NetworkThreadStatus.ConnectionFailed; break; } } } if (socket == null) { // Wait the timeout period before attempting to reconnect. yield return(Workthread.CreateWait(connectionPollTimeSec)); } } timer.Start(); // Read while connected. while (!_quitFlag && TcpClientUtil.Connected(socket)) { // We have a connection. Read messages while we can. if (socket.Available > 0) { // Data available. Read from the network stream into a buffer and attempt to // read a valid message. packetBuffer.Append(socket.GetStream(), socket.Available); PacketBuffer completedPacket; bool crcOk = true; while ((completedPacket = packetBuffer.PopPacket(out crcOk)) != null || !crcOk) { if (crcOk) { // Decode and decompress collated packets. This will just return the same packet // if not collated. _collatedDecoder.SetPacket(completedPacket); while ((completedPacket = _collatedDecoder.Next()) != null) { if (completedPacket.Header.RoutingID == (ushort)RoutingID.Control) { ushort controlMessageId = completedPacket.Header.MessageID; if (controlMessageId == (ushort)ControlMessageID.EndFrame) { // Add a frame flush flag to every end frame message to ensure the render thread renders. // TODO: consider a way to frame skip in a live visualisation link. byte[] packetData = completedPacket.Data; int memberOffset = PacketHeader.Size + Marshal.OffsetOf(typeof(ControlMessage), "ControlFlags").ToInt32(); uint controlFlags = BitConverter.ToUInt32(packetData, memberOffset); controlFlags = Endian.FromNetwork(controlFlags); // Add the flush flag controlFlags |= (uint)EndFrameFlag.Flush; // Convert back to bytes and copy into the packet buffer. byte[] frameNumberBytes = BitConverter.GetBytes(Endian.ToNetwork(controlFlags)); Array.Copy(frameNumberBytes, 0, packetData, memberOffset, frameNumberBytes.Length); // Recalculate the CRC as we've modified the packet. completedPacket.UpdateCrc(); // Update the frame timer.Stop(); FrameTime = timer.ElapsedMilliseconds * 1e-3f; timer.Reset(); timer.Start(); ++_currentFrame; ++_totalFrames; } } _packetQueue.Enqueue(completedPacket); } } else { // TODO: Log CRC failure. } } } else { yield return(null); } } // Disconnected. if (socket != null) { socket.LingerState.Enabled = false; socket.Close(); socket = null; } if (_connection.Connected) { Status = NetworkThreadStatus.Disconnected; _connection.Connected = false; } if (!_connection.AutoReconnect) { break; } Status = NetworkThreadStatus.Reconnecting; } }