/** * Starting the TCP sub thread. */ public void StartProfiling() { IPAddress validIp; if (IPAddress.TryParse(ipAddressString, out validIp) == false) { UnityEngine.Debug.LogWarning("[CRIWARE] (Profiler) IP address not valid - connection aborted. "); return; } TcpParams tcpParams = new TcpParams( validIp, TCP_PORT, TCP_CHUNK, TCP_CONNECT_TIMEOUT_MS, TCP_RETRY_INTERVAL_MS, TCP_RETRY, BUFFERING_INTERVAL_MS); const int READ_INTERVAL_MS = 0; if ((threadTcpClient == null || threadTcpClient.IsAlive == false) && (threadPacketReading == null || threadPacketReading.IsAlive == false) ) { InitVals(); threadTerminator.Reset(); threadTcpClient = new Thread(() => TaskTcpClient(tcpParams)); threadPacketReading = new Thread(() => TaskPacketReading(READ_INTERVAL_MS)); threadTcpClient.Start(); threadPacketReading.Start(); } }
/** * TCP connection sub thread task. */ private void TaskTcpClient(TcpParams tcpParams) { int failedConnectCnt = 0; this.isProfiling = true; using (var tcpClient = new TcpClient()) { while (true) { try { tcpClient.Connect(tcpParams.ipAddress, tcpParams.port); this.isConnected = true; UnityEngine.Debug.Log("[CRIWARE] CRI Profiler connected."); BufferingLoop(tcpClient, tcpParams); } catch (SocketException) { failedConnectCnt += 1; if (failedConnectCnt > tcpParams.connectionRetryLimit) { UnityEngine.Debug.LogWarning("[CRIWARE] Retry count exceeded limit(" + tcpParams.connectionRetryLimit + "); Stopped."); threadTerminator.Set(); } else { UnityEngine.Debug.LogWarning("[CRIWARE] Unable to connect CRI profiler. (Check if \"Uses In Game Preview\" is turned on)" + "\nWaiting for " + (tcpParams.connectionRetryIntervalMillisec / 1000.0f).ToString("F1") + " seconds to reconnect... (" + failedConnectCnt + "/" + tcpParams.connectionRetryLimit + " tries)"); } } this.isConnected = false; if (threadTerminator.WaitOne(tcpParams.connectionRetryIntervalMillisec)) { UnityEngine.Debug.Log("[CRIWARE] CRI Profiler disconnected."); this.isProfiling = false; break; } } } }
/** * Looping process to push the socket input to the buffer. */ private void BufferingLoop(TcpClient tcpClient, TcpParams tcpParams) { int numBytesRead = 0; byte[] chunk = new byte[tcpParams.chunkSize]; byte[] sendPacket; bool enbufferRes = true; this.TcpBuffer.Clear(); using (var netStream = tcpClient.GetStream()) { if (netStream == null) { UnityEngine.Debug.LogError("[CRIWARE] (Profiler) TCP connection not available."); return; } if (netStream.CanRead == false) { UnityEngine.Debug.LogError("[CRIWARE] (Profiler) TCP connection not readable."); return; } sendPacket = MakeLogPacket4StartStopLog(SendPacketType.StartLog); if (sendPacket != null && netStream.CanWrite) { netStream.Write(sendPacket, 0, sendPacket.Length); } while (true) { try { if (netStream.DataAvailable) { numBytesRead = netStream.Read(chunk, 0, chunk.Length); if (this.isBufferCorrupted == false) { lock (this.TcpBuffer) { enbufferRes = this.TcpBuffer.EnBuffer(chunk, numBytesRead); } } if (enbufferRes == false) { UnityEngine.Debug.LogWarning("[CRIWARE] TCP reading buffer overflowed."); /** * -- buffer corrupted -> prepare to reset -- * Enbuffer failure may cause incomplete packets in the packet queue. * The solution we take is to skip all incoming data until a "tail" chunk (followed by no data) arrives, * right after which the buffer will be reset. */ this.isBufferCorrupted = true; } } else { if (this.isBufferCorrupted == true) { lock (this.TcpBuffer) { /* reset the corrupted buffer when all available data are received */ this.TcpBuffer.Clear(); } this.isBufferCorrupted = false; } } } catch (System.IO.IOException) { threadTerminator.Set(); } if (threadTerminator.WaitOne(tcpParams.enBufferIntervalMillisec)) { break; } } sendPacket = MakeLogPacket4StartStopLog(SendPacketType.StopLog); if (sendPacket != null && netStream.CanWrite) { netStream.Write(sendPacket, 0, sendPacket.Length); } } }