/// <summary> /// Конструктор /// </summary> public CommTcpClientLogic() : base() { settings = new Settings(); tcpConnList = null; sharedTcpConn = null; }
/// <summary> /// Остановить работу канала связи /// </summary> public override void Stop() { try { // остановка потока взаимодействия с клиентами StopThread(); } finally { try { // остановка прослушивателя соединений if (tcpListener != null) { tcpListener.Stop(); tcpListener = null; WriteToLog(""); WriteToLog(string.Format(Localization.UseRussian ? "{0} Прослушиватель соединений остановлен" : "{0} Connection listener is stopped", CommUtils.GetNowDT())); } } finally { // отключение всех клиентов lock (tcpConnList) { foreach (TcpConnection tcpConn in tcpConnList) { tcpConn.Close(); } tcpConnList.Clear(); sharedTcpConn = null; } // вызов метода базового класса base.Stop(); } } }
/// <summary> /// Инициализировать канал связи /// </summary> public override void Init(SortedList <string, string> commCnlParams, List <KPLogic> kpList) { // вызов метода базового класса base.Init(commCnlParams, kpList); // инициализация настроек канала связи settings.Init(commCnlParams); // создание соединений и установка соединений КП if (settings.ConnMode == ConnectionModes.Shared) { // общее соединение для всех КП sharedTcpConn = new TcpConnection(new TcpClient()); sharedTcpConn.ReconnectAfter = settings.ReconnectAfter; foreach (KPLogic kpLogic in kpList) { kpLogic.Connection = sharedTcpConn; } } else { // индивидуальное соединение для каждого КП или группы КП с общим позывным tcpConnList = new List <TcpConnection>(); foreach (List <KPLogic> kpByCallNumList in kpCallNumDict.Values) { foreach (KPLogic kpLogic in kpByCallNumList) { TcpConnection tcpConn = new TcpConnection(new TcpClient()); tcpConn.ReconnectAfter = settings.ReconnectAfter; tcpConnList.Add(tcpConn); tcpConn.AddRelatedKP(kpLogic); kpLogic.Connection = tcpConn; } } } // проверка поддержки режима работы канала связи подключенными КП CheckBehaviorSupport(); }
/// <summary> /// Цикл приёма данных по индивидуальным соединениям в режиме ведомого (метод вызывается в отдельном потоке) /// </summary> protected void ListenIndividualConn() { try { while (!terminated) { foreach (KPLogic kpLogic in kpList) { TcpConnection tcpConn = kpLogic.Connection as TcpConnection; if (tcpConn != null && tcpConn.TcpClient.Available > 0) { KPLogic targetKP = kpLogic; if (!ExecProcUnreadIncomingReq(kpLogic, tcpConn, ref targetKP)) { sharedTcpConn.ClearNetStream(inBuf); } } } Thread.Sleep(SlaveThreadDelay); } } catch (Exception ex) { // данное исключение возникать не должно if (Localization.UseRussian) { WriteToLog("Ошибка при приёме данных по индивидуальным соединениям: " + ex.Message); WriteToLog("Приём данных прекращён"); } else { WriteToLog("Error receiving data via individual connections: " + ex.Message); WriteToLog("Data receiving is terminated"); } } }
/// <summary> /// Выполнить действия перед сеансом опроса КП или отправкой команды /// </summary> public override void BeforeSession(KPLogic kpLogic) { // установка соединения при необходимости TcpConnection tcpConn = kpLogic.Connection as TcpConnection; if (tcpConn != null && !tcpConn.Connected) { try { // определение IP-адреса и TCP-порта IPAddress addr; int port; if (tcpConn == sharedTcpConn) { addr = IPAddress.Parse(settings.IpAddress); port = settings.TcpPort; } else { CommUtils.ExtractAddrAndPort(kpLogic.CallNum, settings.TcpPort, out addr, out port); } // установка соединения WriteToLog(""); WriteToLog(string.Format(Localization.UseRussian ? "{0} Установка TCP-соединения с {1}:{2}" : "{0} Establish a TCP connection with {1}:{2}", CommUtils.GetNowDT(), addr, port)); tcpConn.Open(addr, port); } catch (Exception ex) { WriteToLog(ex.Message); } } }
/// <summary> /// Цикл взаимодействия с TCP-клиентами (метод вызывается в отдельном потоке) /// </summary> protected void Execute() { // сохранение в локальных переменных постоянно используемых значений int inactiveTime = settings.InactiveTime; bool devSelByIPAddress = settings.DevSelMode == DeviceSelectionModes.ByIPAddress; int threadDelay = slaveBehavior ? SlaveThreadDelay : MasterThreadDelay; // выбор метода обработки доступных данных Action <TcpConnection> procAvailableData; if (sharedConnMode) { procAvailableData = ProcAvailableDataShared; } else { procAvailableData = ProcAvailableDataIndiv; } // цикл взаимодействия с TCP-клиентами while (!terminated) { TcpConnection tcpConn = null; try { lock (tcpConnList) { // открытие запрашиваемых соединений while (tcpListener.Pending() && !terminated) { TcpClient tcpClient = tcpListener.AcceptTcpClient(); tcpConn = new TcpConnection(tcpClient); tcpConn.WriteToLog = WriteToLog; WriteToLog(string.Format(Localization.UseRussian ? "{0} Соединение с клиентом {1}" : "{0} Connect to the client {1}", CommUtils.GetNowDT(), tcpConn.RemoteAddress)); tcpConnList.Add(tcpConn); // установка соединения всем КП if (sharedConnMode) { SetConnectionToAllKPs(tcpConn); } // привязка соединения к КП по IP-адресу else if (devSelByIPAddress && !BindConnByIP(tcpConn)) { tcpConn.Broken = true; } } // работа с открытыми соединениями DateTime nowDT = DateTime.Now; int connInd = 0; while (connInd < tcpConnList.Count && !terminated) { tcpConn = tcpConnList[connInd]; // приём и обработка данных от TCP-клиента if (tcpConn.TcpClient.Available > 0) { procAvailableData(tcpConn); } // закрытие соединения, если оно неактивно if ((nowDT - tcpConn.ActivityDT).TotalSeconds > inactiveTime || tcpConn.Broken) { WriteToLog(string.Format(Localization.UseRussian ? "{0} Отключение клиента {1}" : "{0} Disconnect the client {1}", nowDT.ToString(CommUtils.CommLineDTFormat), tcpConn.RemoteAddress)); tcpConn.Close(); tcpConnList.RemoveAt(connInd); } else { connInd++; } } } } catch (Exception ex) { if (tcpConn == null) { WriteToLog(string.Format(Localization.UseRussian ? "Ошибка при взаимодействии с клиентами: {0}" : "Error communicating with clients: {0}", ex.Message)); } else { WriteToLog(string.Format(Localization.UseRussian ? "Ошибка при взаимодействии с клиентом {0}: {1}" : "Error communicating with the client {0}: {1}", tcpConn.RemoteAddress, ex.Message)); } } Thread.Sleep(threadDelay); } }
/// <summary> /// Установить соединение всем КП на линии связи /// </summary> protected void SetConnectionToAllKPs(TcpConnection tcpConn) { if (sharedTcpConn != null) sharedTcpConn.Broken = true; sharedTcpConn = tcpConn; foreach (KPLogic kpLogic in kpList) kpLogic.Connection = sharedTcpConn; }
/// <summary> /// Остановить работу канала связи /// </summary> public override void Stop() { try { // остановка потока взаимодействия с клиентами StopThread(); } finally { try { // остановка прослушивателя соединений if (tcpListener != null) { tcpListener.Stop(); tcpListener = null; WriteToLog(""); WriteToLog(string.Format(Localization.UseRussian ? "{0} Прослушиватель соединений остановлен" : "{0} Connection listener is stopped", CommUtils.GetNowDT())); } } finally { // отключение всех клиентов lock (tcpConnList) { foreach (TcpConnection tcpConn in tcpConnList) tcpConn.Close(); tcpConnList.Clear(); sharedTcpConn = null; } // вызов метода базового класса base.Stop(); } } }
/// <summary> /// Инициализировать канал связи /// </summary> public override void Init(SortedList<string, string> commCnlParams, List<KPLogic> kpList) { // вызов метода базового класса base.Init(commCnlParams, kpList); // инициализация настроек канала связи settings.Init(commCnlParams); // создание соединений и установка соединений КП if (settings.ConnMode == ConnectionModes.Shared) { // общее соединение для всех КП sharedTcpConn = new TcpConnection(new TcpClient()); foreach (KPLogic kpLogic in kpList) kpLogic.Connection = sharedTcpConn; } else { // индивидуальное соединение для каждого КП или группы КП с общим позывным tcpConnList = new List<TcpConnection>(); foreach (List<KPLogic> kpByCallNumList in kpCallNumDict.Values) { foreach (KPLogic kpLogic in kpByCallNumList) { int timeout = kpLogic.ReqParams.Timeout; TcpConnection tcpConn = new TcpConnection(new TcpClient()); tcpConnList.Add(tcpConn); tcpConn.AddRelatedKP(kpLogic); kpLogic.Connection = tcpConn; } } } // проверка поддержки режима работы канала связи подключенными КП CheckBehaviorSupport(); }
/// <summary> /// Привязать соединение к КП, используя библиотеку КП /// </summary> protected void BindConnByDeviceLibrary(TcpConnection tcpConn, KPLogic kpLogic) { if (kpLogic != null) { WriteToLog(string.Format(Localization.UseRussian ? "{0} Клиент {1} привязан к {2}, используя библиотеку КП" : "{0} The client {1} is bound to the {2} using a device library", CommUtils.GetNowDT(), tcpConn.RemoteAddress, kpLogic.Caption)); SetConnection(kpLogic, tcpConn); } else { WriteToLog(string.Format(Localization.UseRussian ? "{0} Не удалось привязать клиента {1} к КП, используя библиотеку КП" : "{0} Unable to bind the client {1} to a device using a device library", CommUtils.GetNowDT(), tcpConn.RemoteAddress)); } }
/// <summary> /// Принять первый пакет данных, содержащий позывной /// </summary> protected string ReceiveFirstPackage(TcpConnection tcpConn) { WriteToLog(string.Format(Localization.UseRussian ? "{0} Приём первого пакета данных от клиента {1}" : "{0} Receive the first data package from the client {1}", CommUtils.GetNowDT(), tcpConn.RemoteAddress)); string logText; int readCnt = tcpConn.ReadAvailable(inBuf, 0, CommUtils.ProtocolLogFormats.String, out logText); WriteToLog(logText); return readCnt > 0 ? Encoding.Default.GetString(inBuf, 0, readCnt) : ""; }
/// <summary> /// Привязать соединение к КП по IP-адресу /// </summary> protected bool BindConnByIP(TcpConnection tcpConn) { List<KPLogic> kpByCallNumList; // список КП с общим позывным string nowDTStr = CommUtils.GetNowDT(); if (kpCallNumDict.TryGetValue(tcpConn.RemoteAddress, out kpByCallNumList)) { foreach (KPLogic kpLogic in kpByCallNumList) { WriteToLog(string.Format(Localization.UseRussian ? "{0} Клиент {1} привязан к {2} по IP-адресу" : "{0} The client {1} is bound to the {2} by IP address", nowDTStr, tcpConn.RemoteAddress, kpLogic.Caption)); SetConnection(kpLogic, tcpConn); } return true; } else { WriteToLog(string.Format(Localization.UseRussian ? "{0} Не удалось привязать клиента {1} к КП по IP-адресу" : "{0} Unable to bind the client {1} to a device by IP address", nowDTStr, tcpConn.RemoteAddress)); return false; } }
/// <summary> /// Привязать соединение к КП по позывному /// </summary> protected bool BindConnByFirstPackage(TcpConnection tcpConn, string firstPackage) { List<KPLogic> kpByCallNumList; // список КП с одинаковым позывным string nowDTStr = CommUtils.GetNowDT(); if (kpCallNumDict.TryGetValue(firstPackage, out kpByCallNumList)) { foreach (KPLogic kpLogic in kpByCallNumList) { WriteToLog(string.Format(Localization.UseRussian ? "{0} Клиент {1} привязан к {2} по первому пакету данных" : "{0} The client {1} is bound to the {2} by first data package", nowDTStr, tcpConn.RemoteAddress, kpLogic.Caption)); SetConnection(kpLogic, tcpConn); } return true; } else { WriteToLog(string.Format(Localization.UseRussian ? "{0} Не удалось привязать клиента {1} к КП по первому пакету данных" : "{0} Unable to bind the client {1} to a device by first data package", nowDTStr, tcpConn.RemoteAddress)); return false; } }
/// <summary> /// Конструктор /// </summary> public CommTcpServerLogic() : base() { slaveBehavior = false; sharedConnMode = false; devSelByFirstPackage = false; devSelByDeviceLibrary = false; settings = new Settings(); tcpListener = null; tcpConnList = new List<TcpConnection>(); sharedTcpConn = null; }
/// <summary> /// Установить соединение для КП /// </summary> protected void SetConnection(KPLogic kpLogic, TcpConnection tcpConn) { TcpConnection existingTcpConn = kpLogic.Connection as TcpConnection; if (existingTcpConn != null) { existingTcpConn.Broken = true; existingTcpConn.ClearRelatedKPs(); } kpLogic.Connection = tcpConn; tcpConn.AddRelatedKP(kpLogic); }
/// <summary> /// Обработать доступные данные в режиме соединения Shared /// </summary> protected void ProcAvailableDataShared(TcpConnection tcpConn) { // обработка входящего запроса в режиме ведомого для произвольного КП if (tcpConn == sharedTcpConn && slaveBehavior && firstKP != null) { KPLogic targetKP = null; if (!ExecProcUnreadIncomingReq(firstKP, tcpConn, ref targetKP)) tcpConn.ClearNetStream(inBuf); } }
/// <summary> /// Обработать доступные данные в режиме соединения Individual /// </summary> protected void ProcAvailableDataIndiv(TcpConnection tcpConn) { if (tcpConn.RelatedKPExists) { // обработка входящего запроса в режиме ведомого для первого КП из группы с одинаковым позывным if (slaveBehavior) { KPLogic targetKP = tcpConn.GetFirstRelatedKP(); if (!ExecProcUnreadIncomingReq(targetKP, tcpConn, ref targetKP)) tcpConn.ClearNetStream(inBuf); } } else { // привязка соединения к КП по первому пакету данных if (devSelByFirstPackage) { if (tcpConn.JustConnected) { string firstPackage = ReceiveFirstPackage(tcpConn); if (!BindConnByFirstPackage(tcpConn, firstPackage)) tcpConn.Broken = true; } } else if (devSelByDeviceLibrary) { // привязка соединения к КП, используя произвольную библиотеку КП if (kpListNotEmpty) { KPLogic targetKP = null; if (!ExecProcUnreadIncomingReq(firstKP, tcpConn, ref targetKP)) tcpConn.ClearNetStream(inBuf); BindConnByDeviceLibrary(tcpConn, targetKP); } } } tcpConn.JustConnected = false; }
/// <summary> /// Цикл взаимодействия с TCP-клиентами (метод вызывается в отдельном потоке) /// </summary> protected void Execute() { // сохранение в локальных переменных постоянно используемых значений int inactiveTime = settings.InactiveTime; bool devSelByIPAddress = settings.DevSelMode == DeviceSelectionModes.ByIPAddress; int threadDelay = slaveBehavior ? SlaveThreadDelay : MasterThreadDelay; // выбор метода обработки доступных данных Action<TcpConnection> procAvailableData; if (sharedConnMode) procAvailableData = ProcAvailableDataShared; else procAvailableData = ProcAvailableDataIndiv; // цикл взаимодействия с TCP-клиентами while (!terminated) { TcpConnection tcpConn = null; try { lock (tcpConnList) { // открытие запрашиваемых соединений while (tcpListener.Pending() && !terminated) { TcpClient tcpClient = tcpListener.AcceptTcpClient(); tcpConn = new TcpConnection(tcpClient); tcpConn.WriteToLog = WriteToLog; WriteToLog(string.Format(Localization.UseRussian ? "{0} Соединение с клиентом {1}" : "{0} Connect to the client {1}", CommUtils.GetNowDT(), tcpConn.RemoteAddress)); tcpConnList.Add(tcpConn); // установка соединения всем КП if (sharedConnMode) SetConnectionToAllKPs(tcpConn); // привязка соединения к КП по IP-адресу else if (devSelByIPAddress && !BindConnByIP(tcpConn)) tcpConn.Broken = true; } // работа с открытыми соединениями DateTime nowDT = DateTime.Now; int connInd = 0; while (connInd < tcpConnList.Count && !terminated) { tcpConn = tcpConnList[connInd]; // приём и обработка данных от TCP-клиента if (tcpConn.TcpClient.Available > 0) procAvailableData(tcpConn); // закрытие соединения, если оно неактивно if ((nowDT - tcpConn.ActivityDT).TotalSeconds > inactiveTime || tcpConn.Broken) { WriteToLog(string.Format(Localization.UseRussian ? "{0} Отключение клиента {1}" : "{0} Disconnect the client {1}", nowDT.ToString(CommUtils.CommLineDTFormat), tcpConn.RemoteAddress)); tcpConn.Close(); tcpConnList.RemoveAt(connInd); } else { connInd++; } } } } catch (Exception ex) { if (tcpConn == null) WriteToLog(string.Format(Localization.UseRussian ? "Ошибка при взаимодействии с клиентами: {0}" : "Error communicating with clients: {0}", ex.Message)); else WriteToLog(string.Format(Localization.UseRussian ? "Ошибка при взаимодействии с клиентом {0}: {1}" : "Error communicating with the client {0}: {1}", tcpConn.RemoteAddress, ex.Message)); } Thread.Sleep(threadDelay); } }