/// <summary> /// Receives an identification packet. /// </summary> protected bool ReceiveHelloPacket(TcpConnection conn, out string helloStr, out string helloHex) { Log.WriteAction(Locale.IsRussian ? "Приём идентификационного пакета данных от клиента {0}" : "Receive an identification packet from the client {0}", conn.RemoteAddress); int readCnt = conn.ReadAvailable(inBuf, 0, HelloPacketLength, ProtocolFormat.String, out string logText); Log.WriteLine(logText); if (readCnt > 0) { helloStr = conn.Encoding.GetString(inBuf, 0, readCnt); helloHex = "0x" + ScadaUtils.BytesToHex(inBuf, 0, readCnt); return(true); } else { helloStr = ""; helloHex = ""; return(false); } }
/// <summary> /// Makes the communication channel ready for operating. /// </summary> public override void MakeReady() { CheckBehaviorSupport(); if (options.ConnectionMode == ConnectionMode.Individual) { indivConnList = new List <TcpConnection>(); DeviceDictionary deviceDict = new DeviceDictionary(); deviceDict.AddRange(LineContext.SelectDevices()); foreach (DeviceDictionary.DeviceGroup deviceGroup in deviceDict.SelectDeviceGroups()) { TcpConnection conn = new TcpConnection(Log, new TcpClient()) { ReconnectAfter = options.ReconnectAfter }; indivConnList.Add(conn); foreach (DeviceLogic deviceLogic in deviceGroup) { conn.BindDevice(deviceLogic); deviceLogic.Connection = conn; } } } else // ConnectionMode.Shared { sharedConn = new TcpConnection(Log, new TcpClient()) { ReconnectAfter = options.ReconnectAfter }; SetDeviceConnection(sharedConn); } }
/// <summary> /// Communication cycle running in a separate thread. /// </summary> protected void Execute() { int threadDelay = options.Behavior == ChannelBehavior.Slave ? SlaveThreadDelay : ScadaUtils.ThreadDelay; TimeSpan clientLifetime = TimeSpan.FromSeconds(options.ClientLifetime); while (!terminated) { TcpConnection conn = null; try { // open incoming connections while (tcpListener.Pending() && !terminated) { Log.WriteAction(Locale.IsRussian ? "Соединение с клиентом {0}" : "Connect to the client {0}", conn.RemoteAddress); conn = new TcpConnection(Log, tcpListener.AcceptTcpClient()); if (options.ConnectionMode == ConnectionMode.Shared) { BindDevices(conn, LineContext.SelectDevices()); } else if (options.DeviceMapping == DeviceMapping.ByIPAddress) { if (deviceDict.GetDeviceGroup(conn.RemoteAddress, out DeviceDictionary.DeviceGroup deviceGroup)) { BindDevices(conn, deviceGroup); } else { Log.WriteError(CommPhrases.UnableFindDevice, conn.RemoteAddress); conn.CloseMark = true; } } lock (connList) { connList.Add(conn); } } // receive data from connected clients DateTime utcNow = DateTime.UtcNow; int connIdx = 0; while (connIdx < connList.Count && !terminated) { conn = connList[connIdx]; lock (conn) { // receive available data if (conn.TcpClient.Available > 0 && !conn.CloseMark) { ReceiveData(conn); } // close inactive connection if (utcNow - conn.ActivityTime > clientLifetime || conn.CloseMark) { Log.WriteAction(Locale.IsRussian ? "Отключение клиента {0}" : "Disconnect the client {0}", conn.RemoteAddress); conn.Close(); lock (connList) { connList.RemoveAt(connIdx); } } else { connIdx++; } } } } catch (Exception ex) { if (conn == null) { Log.WriteException(ex, Locale.IsRussian ? "Ошибка при взаимодействии с клиентами" : "Error communicating with clients"); } else { Log.WriteException(ex, Locale.IsRussian ? "Ошибка при взаимодействии с клиентом {0}" : "Error communicating with the client {0}", conn.RemoteAddress); } } finally { Thread.Sleep(threadDelay); } } }