/// <summary> /// Process data received by UDP. /// </summary> protected void UdpReceiveCallback(IAsyncResult ar) { byte[] buf = null; if (!terminated) { try { IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0); buf = slaveConn.UdpClient.EndReceive(ar, ref remoteEP); slaveConn.RemoteAddress = remoteEP.Address.ToString(); slaveConn.RemotePort = remoteEP.Port; Log.WriteLine(); Log.WriteAction(Locale.IsRussian ? "Получены данные от {0}:{1}" : "Data received from {0}:{1}", slaveConn.RemoteAddress, slaveConn.RemotePort); if (buf == null) { Log.WriteAction(Locale.IsRussian ? "Данные пусты" : "Data is empty"); } } catch (Exception ex) { Log.WriteException(ex, Locale.IsRussian ? "Ошибка при приёме данных" : "Error receiving data"); } } if (buf != null) { if (options.DeviceMapping == DeviceMapping.ByIPAddress) { if (deviceDict.GetDeviceGroup(slaveConn.RemoteAddress, out DeviceDictionary.DeviceGroup deviceGroup)) { lock (deviceLock) { // process the incoming request for the devices with the specified IP address ProcessIncomingRequest(deviceGroup, buf, 0, buf.Length, requestArgs); } } else { Log.WriteError(CommPhrases.UnableFindDevice, slaveConn.RemoteAddress); } } else if (options.DeviceMapping == DeviceMapping.ByDriver) { lock (deviceLock) { // process the incoming request for any device ProcessIncomingRequest(LineContext.SelectDevices(), buf, 0, buf.Length, requestArgs); } } } if (!terminated) { slaveConn.BeginReceive(UdpReceiveCallback); } }
/// <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); } } }