// Aborts all related endpoint threads and data public void stop() { fullyStopped = true; Thread.Sleep(50); // clear any last messages state = RemoteEndpointState.Closed; running = false; Thread.Sleep(50); // wait for threads to stop lock (sendQueueMessagesHighPriority) { sendQueueMessagesHighPriority.Clear(); } lock (sendQueueMessagesNormalPriority) { sendQueueMessagesNormalPriority.Clear(); } lock (sendQueueMessagesLowPriority) { sendQueueMessagesLowPriority.Clear(); } lock (recvRawQueueMessages) { recvRawQueueMessages.Clear(); } lock (subscribedAddresses) { subscribedAddresses.Clear(); } // Abort all related threads if (recvThread != null) { //recvThread.Abort(); recvThread = null; } if (sendThread != null) { //sendThread.Abort(); sendThread = null; } if (parseThread != null) { //parseThread.Abort(); parseThread = null; } disconnect(); }
// Internal function that sends data through the socket protected void sendDataInternal(ProtocolMessageCode code, byte[] data, byte[] checksum) { byte[] ba = CoreProtocolMessage.prepareProtocolMessage(code, data, checksum); NetDump.Instance.appendSent(clientSocket, ba, ba.Length); try { for (int sentBytes = 0; sentBytes < ba.Length && running;) { int bytesToSendCount = ba.Length - sentBytes; if (bytesToSendCount > 8000) { bytesToSendCount = 8000; } int curSentBytes = clientSocket.Send(ba, sentBytes, bytesToSendCount, SocketFlags.None); lastDataSentTime = Clock.getTimestamp(); // Sleep a bit to allow other threads to do their thing Thread.Yield(); sentBytes += curSentBytes; // TODO TODO TODO timeout } if (clientSocket.Connected == false) { if (running) { Logging.warn(String.Format("sendRE: Failed senddata to remote endpoint {0}, Closing.", getFullAddress())); } state = RemoteEndpointState.Closed; } } catch (Exception e) { if (running) { Logging.warn(String.Format("sendRE: Socket exception for {0}, closing. {1}", getFullAddress(), e)); } state = RemoteEndpointState.Closed; } }
public void start(Socket socket = null) { if (fullyStopped) { Logging.error("Can't start a fully stopped RemoteEndpoint"); return; } if (running) { return; } if (socket != null) { clientSocket = socket; } if (clientSocket == null) { Logging.error("Could not start NetworkRemoteEndpoint, socket is null"); return; } prepareSocket(clientSocket); remoteIP = (IPEndPoint)clientSocket.RemoteEndPoint; address = remoteIP.Address.ToString(); fullAddress = address + ":" + remoteIP.Port; presence = null; presenceAddress = null; connectionStartTime = Clock.getTimestamp(); lock (subscribedAddresses) { subscribedAddresses.Clear(); } lastDataReceivedTime = Clock.getTimestamp(); lastDataSentTime = Clock.getTimestamp(); state = RemoteEndpointState.Established; timeDifference = 0; timeSyncComplete = false; timeSyncs.Clear(); running = true; // Abort all related threads if (recvThread != null) { recvThread.Abort(); recvThread = null; } if (sendThread != null) { sendThread.Abort(); sendThread = null; } if (parseThread != null) { parseThread.Abort(); parseThread = null; } try { TLC = new ThreadLiveCheck(); // Start receive thread recvThread = new Thread(new ThreadStart(recvLoop)); recvThread.Name = "Network_Remote_Endpoint_Receive_Thread"; recvThread.Start(); // Start send thread sendThread = new Thread(new ThreadStart(sendLoop)); sendThread.Name = "Network_Remote_Endpoint_Send_Thread"; sendThread.Start(); // Start parse thread parseThread = new Thread(new ThreadStart(parseLoop)); parseThread.Name = "Network_Remote_Endpoint_Parse_Thread"; parseThread.Start(); } catch (Exception e) { Logging.error("Exception start remote endpoint: {0}", e.Message); } }
// Send thread protected void sendLoop() { // Prepare an special message object to use while sending, without locking up the queue messages QueueMessage active_message = new QueueMessage(); if (enableSendTimeSyncMessages) { sendTimeSyncMessages(); } int messageCount = 0; while (running) { TLC.Report(); long curTime = Clock.getTimestamp(); if (helloReceived == false && curTime - connectionStartTime > 10) { // haven't received hello message for 10 seconds, stop running Logging.warn(String.Format("Node {0} hasn't received hello data from remote endpoint for over 10 seconds, disconnecting.", getFullAddress())); state = RemoteEndpointState.Closed; running = false; break; } if (curTime - lastDataReceivedTime > CoreConfig.pingTimeout) { // haven't received any data for 10 seconds, stop running Logging.warn(String.Format("Node {0} hasn't received any data from remote endpoint for over {1} seconds, disconnecting.", getFullAddress(), CoreConfig.pingTimeout)); state = RemoteEndpointState.Closed; running = false; break; } if (curTime - lastDataSentTime > CoreConfig.pongInterval) { try { clientSocket.Send(new byte[1] { 1 }, SocketFlags.None); lastDataSentTime = curTime; continue; } catch (Exception) { state = RemoteEndpointState.Closed; running = false; break; } } bool message_found = false; lock (sendQueueMessagesHighPriority) { lock (sendQueueMessagesNormalPriority) { if ((messageCount > 0 && messageCount % 5 == 0) || (sendQueueMessagesNormalPriority.Count == 0 && sendQueueMessagesHighPriority.Count == 0)) { lock (sendQueueMessagesLowPriority) { if (sendQueueMessagesLowPriority.Count > 0) { // Pick the oldest message QueueMessage candidate = sendQueueMessagesLowPriority[0]; active_message.code = candidate.code; active_message.data = candidate.data; active_message.checksum = candidate.checksum; active_message.skipEndpoint = candidate.skipEndpoint; active_message.helperData = candidate.helperData; // Remove it from the queue sendQueueMessagesLowPriority.Remove(candidate); message_found = true; } } messageCount = 0; } if (message_found == false && ((messageCount > 0 && messageCount % 3 == 0) || sendQueueMessagesHighPriority.Count == 0)) { if (sendQueueMessagesNormalPriority.Count > 0) { // Pick the oldest message QueueMessage candidate = sendQueueMessagesNormalPriority[0]; active_message.code = candidate.code; active_message.data = candidate.data; active_message.checksum = candidate.checksum; active_message.skipEndpoint = candidate.skipEndpoint; active_message.helperData = candidate.helperData; // Remove it from the queue sendQueueMessagesNormalPriority.Remove(candidate); message_found = true; } } if (message_found == false && sendQueueMessagesHighPriority.Count > 0) { // Pick the oldest message QueueMessage candidate = sendQueueMessagesHighPriority[0]; active_message.code = candidate.code; active_message.data = candidate.data; active_message.checksum = candidate.checksum; active_message.skipEndpoint = candidate.skipEndpoint; active_message.helperData = candidate.helperData; // Remove it from the queue sendQueueMessagesHighPriority.Remove(candidate); message_found = true; } } } if (message_found) { messageCount++; // Active message set, attempt to send it sendDataInternal(active_message.code, active_message.data, active_message.checksum); if (active_message.code == ProtocolMessageCode.bye) { Thread.Sleep(500); // grace sleep to get the message through running = false; fullyStopped = true; } Thread.Sleep(1); } else { // Sleep for 10ms to prevent cpu waste Thread.Sleep(10); } } }
// Receive thread protected virtual void recvLoop() { socketReadBuffer = new byte[8192]; lastMessageStatTime = DateTime.UtcNow; while (running) { TLC.Report(); // Let the protocol handler receive and handle messages try { byte[] data = readSocketData(); if (data != null) { parseDataInternal(data, this); messagesPerSecond++; } } catch (Exception e) { if (running) { Logging.warn(string.Format("recvRE: Disconnected client {0} with exception {1}", getFullAddress(), e.ToString())); } state = RemoteEndpointState.Closed; } // Check if the client disconnected if (state == RemoteEndpointState.Closed) { running = false; break; } TimeSpan timeSinceLastStat = DateTime.UtcNow - lastMessageStatTime; if (timeSinceLastStat.TotalSeconds < 0 || timeSinceLastStat.TotalSeconds > 2) { lastMessageStatTime = DateTime.UtcNow; lastMessagesPerSecond = (int)(messagesPerSecond / timeSinceLastStat.TotalSeconds); messagesPerSecond = 0; } if (lastMessagesPerSecond < 1) { lastMessagesPerSecond = 1; } // Sleep a while to throttle the client // Check if there are too many messages // TODO TODO TODO this can be handled way better int total_message_count = NetworkQueue.getQueuedMessageCount() + NetworkQueue.getTxQueuedMessageCount(); if (total_message_count > 500) { Thread.Sleep(100 * lastMessagesPerSecond); if (messagesPerSecond == 0) { lastMessageStatTime = DateTime.UtcNow; } lastDataReceivedTime = Clock.getTimestamp(); } else if (total_message_count > 100) { Thread.Sleep(total_message_count / 10); } else { Thread.Sleep(1); } } }