/// <summary> /// Async method that handles connection for each of the connected clients. /// </summary> /// <param name="tcpClient"></param> private void StartNewClient(Object tcpClient) { Boolean runClientThread = true; // Get client var client = (TcpClient)tcpClient; client.ReceiveTimeout = Int32.MaxValue; EndPoint clientAddress = client.Client.RemoteEndPoint; GlobalLogger.SendLogMessage("ServerEvent", "Client Connected {0}", client.Client.RemoteEndPoint.ToString()); // Get client stream and create writer/reader Stream s = client.GetStream(); var br = new BinaryReader(s); var bw = new BinaryWriter(s); // Create Optimizer for this client var optimizer = new DistributionOptimizer(this); #if !DEBUG try { #endif // Start accepting messages while (runClientThread) { while (client.Available < 2) Thread.Sleep(10); // wait 10ms for control code ushort code = br.ReadUInt16(); // read control code switch (code) { case ControlCodes.SendingConfiguration: // configuration data coming! { // read configuration from network stream var cfg = DistributionConfiguration.ReadFromStream(client, br); // Print debug info GlobalLogger.SendLogMessage("Server", "Distribution Configuration Received!"); GlobalLogger.SendLogMessage("Server", "Problem ID: {0}", cfg.ProblemID.ToString()); GlobalLogger.SendLogMessage("Server", "Controller IP: {0}:{1}", cfg.ControllerServer.ToString(), cfg.ControllerServerPort); GlobalLogger.SendLogMessage("Server", "Redis IP: {0}:{1}", cfg.RedisServer.ToString(), cfg.RedisServerPort); GlobalLogger.SendLogMessage("Server", "OSRM IP: {0}:{1}", cfg.OsrmServer.ToString(), cfg.OsrmServerPort); GlobalLogger.SendLogMessage("Server", "Worker Count: {0}", cfg.Workers.Length); GlobalLogger.SendLogMessage("Server", "Task Count: {0}", cfg.Tasks.Length); // initalize the optimizer using the configuration optimizer.Initialize(cfg); // send back acknowledge bw.Write(ControlCodes.Acknowledge); } break; case ControlCodes.StartPreprocessing: { // create a callback delegate, returns true if abort signal received Func<UInt16, Int32, Int32, Boolean> progressCallback = (UInt16 cb_code, Int32 cb_entry, Int32 cb_capacity) => { // send code & progress to controller (10 bytes) bw.Write(cb_code); bw.Write(cb_entry); bw.Write(cb_capacity); // wait for ack/abort orders if needed while (cb_code != ControlCodes.Acknowledge) // if the code is ack there is no need for reply { while (client.Available < 2) ; // wait for either ack or abort, otherwise continue waiting UInt16 cb_orders = br.ReadUInt16(); if (cb_orders == ControlCodes.Acknowledge) return false; else if (cb_orders == ControlCodes.AbortAction) return true; } return false; }; // read configuration from network while (client.Available < 13) ; // wait for data CacheType type = (CacheType)br.ReadByte(); Int64 start = br.ReadInt64(); Int32 length = br.ReadInt32(); GlobalLogger.SendLogMessage("Preprocessing", "Preprocessing parameters received!"); GlobalLogger.SendLogMessage("Preprocessing", "Type = {0}; Start = {1}; Length = {2}", type, start, length); // ack reception of data bw.Write(ControlCodes.Acknowledge); // start work optimizer.PreprocessProblemData(type, start, length, progressCallback); } break; case ControlCodes.TerminateConnection: // Terminate connection! { runClientThread = false; // NOTE release resources here! // Send ACK and terminate connection bw.Write(ControlCodes.Acknowledge); client.Close(); } break; } } #if !DEBUG } catch (ProblemLibException x) // ProblemLibException represents expected errors with assigned error codes { // Expected errors are handed back to the controller GlobalLogger.SendLogMessage("Error", "An expected error was caught in DistributionServer.StartNewClient()"); GlobalLogger.SendLogMessage("Error", "Error-{0}: {1}", x.ErrorCode, x.InnerException != null ? x.InnerException.Message : "null"); // send back error info bw.Write(ControlCodes.Error); bw.Write(x.ErrorCode); bw.Write(x.TimeStamp.Ticks); } catch (Exception ex) // any other exception is unexpected { GlobalLogger.SendLogMessage("Error", "An unexpected exception of type {0} occured: {1}", ex.GetType().FullName, ex.Message); // send back error info bw.Write(ControlCodes.Error); bw.Write(ErrorCodes.UnknownError); bw.Write(DateTime.Now.Ticks); } #endif GlobalLogger.SendLogMessage("ServerEvent", "Client Disconnected {0}", clientAddress.ToString()); }