powered by simpleCommunicator - 2.0.55     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / TCP\SSL-Server на C#
47 сообщений из 47, показаны все 2 страниц
TCP\SSL-Server на C#
    #38468393
JustOxlamon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Привет.

Мне надо написать TCP/SSL server на любом языке, который бы держал около 10к одновременных долгоживущих подключений (онлайн-игра).

Сервер - 4x3.80GhzXeonE5-1620, 65536MBRAMDDR3.

Я написал по примерам в сети небольшой сервер с использованием TcpListener, TcpClient, Thread. Все работает как надо, держит несколько клиентов, в случае необработанных ошибок прибивает только одно соединение, вроде все хорошо, даже пашет SSL, но код выглядит через-чур просто. Из-за чего у меня появился страх, который я пока не знаю как развеять

Итак вопросы.
1) Какие есть материалы в сети, о том как писать подобные сервера?
2) Кто может помочь с написанием высокостабильного сервера (есть готовый протокол) на любом адекватном языке (c#\qt c++) за деньги или советом.

Если чем-то поможет, могу показать код. Может потыкаете носом в проблемы.
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38468573
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
JustOxlamon,

1) Зачем для игры SSL? Какие такие секретные данные он защищает?
2) ИМХО по ощущениям 10к SSL коннектов ваш сервер не выдержит.
3) Давайте описание протокола + код.
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38468597
beg-in-er
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
JustOxlamonСервер - 4x3.80GhzXeonE5-1620, 65536MBRAMDDR3. .
а сделать 2 сервера религия не позволят? сразу будет 5к а не 10к

и да , зачем ССЛ?
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38468697
JustOxlamon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Клиент написан, и меняться ради нашего сервера не будет (ну ведь понятно, что клиент не наш, а вот сервер хотим свой )) )
Поэтому такое требование.

Насчет двух серверов, я не знаю, но вроде до 6 серверов вполне можно. Требование взято с потолка.

кривокод, в зипке:
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38468725
netivan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
JustOxlamon,

честно не смотрел весь код, но я так понимаю каждому соединению свой поток?
Код: c#
1.
 this.clientThread = new Thread(new ThreadStart(Work));


Т.е. при максимальной загрузке у вас будет 10 000 потоков? Я сомневаюсь, что такое будет работать...
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38468727
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
JustOxlamon,

1) Требование полного SSL - это чушь. Но примем за факт.
2) 30 000 коннектов сервер не потянет, нужно балансирование. Смотрите nginx и HAproxy
3) Код, прости господи, хоть и простой, но говеный.

Самая главная претензия - зачем на каждого клиента создавать свой поток? У вас из 30 000. Переключения контекста забьют всю производительность. А ведь еще SSL есть. В общем, асинхронность + TPL (Task и иже с ним). Про async/await не скажу, не тестил.

Далее, зачем использовать синхронную версию AcceptTcpClient?

Обработка сообщений у вас стремная, нет типов. Или они все у вас одного типа?

Обработка исключений отсутствует. Если есть общие данные для всех клиентов, они не кэшируются. Откуда же данные берутся?

Это так, что в глаза сходу бросилось.
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38468736
netivan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Arm79,

про асинхронность подпишусь. Вроде начиная с TPL там делать это совсем легко. А почему думаю сервер 30к соединений не потянет?
В мою бытность было все через BeginXXX,ENDXXX и тд.
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38468737
JustOxlamon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
netivanJustOxlamon,

честно не смотрел весь код, но я так понимаю каждому соединению свой поток?
Код: c#
1.
 this.clientThread = new Thread(new ThreadStart(Work));


Т.е. при максимальной загрузке у вас будет 10 000 потоков? Я сомневаюсь, что такое будет работать...

Я тоже сомневаюсь что сработает, поэтому и спрашиваю тут.
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38468751
JustOxlamon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Arm79,
Про SSL обсудили, это требование клиентской программы, на которую мы не влияем. Поэтому можно смириться.

Гут, со всем остальным согласен. Например, если бы вам дали такую задачу, сколько времени бы она заняла при бюджете в 90к рублей?

Пакеты такие говенные потому, что они все одинаковые. (хотя я бы сделал один базовый, и кучу от него наследовались, бы, ну и все такое по умному, но... )

Общих данных нету. Кешировать нечего. Про качество кода, это лучше не в этом куске обсуждать. Пример на коленке написан, и похож на кусок сами знаете чего.
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38468752
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
netivanА почему думаю сервер 30к соединений не потянет?

Это мое предположение. Не потому, что 30000 - это жутко много для сервера. А потому что будет большая вычислительная нагрузка на шифрование данных. Там, хоть и и используются симметричные шифры, все равно прилично нагружаются. А скорость, как я понимаю, для онлайн-игры важна
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38468758
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
JustOxlamonесли бы вам дали такую задачу, сколько времени бы она заняла при бюджете в 90к рублей?

Мне? При условии наличия полного ТЗ и доступа к тестовому контуру? Неделя, не более. Но я человек занятой, и фрилансить могу не более 2-3 часов в день :-) Так что примерно месяц.
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38468777
JustOxlamon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
В общем как я понял, сильно желательно переписать с использованием асинхронных сокетов.

Ладно, куда копать? Где есть живой пример SSL+ Async Socket?

Кто готов взяться за этот кусок, если хочется денег то 90к в принципе ждут.

В идеале я бы хотел получить DLL с подобными интерфейсами:
(ТЗ вполне можно составить совместно с исполнителем, чтобы не было никаких фантазий)
Вкратце выглядеть может все так:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
interface Client{
  string Login {get;}

  void OnConnect();
  void OnDisconnect();
  void OnError( int Code );
  void OnPaсketReceived( Packet p );

  void WritePacket( Packet p );
}

interface Server{
  void Start(int Port);
  void Stop();
  
  bool ForceDisconnectUser( string Login );
  void SendPacket( string ToLogin, Packet p );
}
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38468782
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вот еще замечания:
1) У вас класс Пакет выполняет сразу несколько функций. И парсинг, и работу с потоком. Нужно разделить его на непосредственно класс Пакет (с бизнес-логикой при необходимости) и класс для работы с потоком.
2) При записи в поток зачем то работа на уровне байтов. Не надо совмещать парсинг и отправку данных, заранее подготовьте пакет и разом пишите его в поток.
3) Побайтное чтение из потока тоже не вдохновляет, в первую очередь своей скоростью. И я не уверен, что вы не напутали с кодировками. У вас и 28591, и utf-8, и неявно Unicode (при добавлении символа в StringBuilder)

(2 и 3 - сделали бы пользовательскую сериализацию своего объекта)

4) Нет очистки sslStream. TcpClient вы закрываете, а его поток - нет
5) Зачем лочить WriteLocker? У вас же один поток на одного клиента. ИМХО лишняя синхронизация
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38468791
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
JustOxlamonКто готов взяться за этот кусок, если хочется денег то 90к в принципе ждут.
Arm79Но я человек занятой, и фрилансить могу не более 2-3 часов в день :-) Так что примерно месяц

Если устроят растянутые сроки, welcome

Ну или пишите сами, здесь подскажут, как правильно.
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38468807
JustOxlamon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Arm79Вот еще замечания:
1) У вас класс Пакет выполняет сразу несколько функций. И парсинг, и работу с потоком. Нужно разделить его на непосредственно класс Пакет (с бизнес-логикой при необходимости) и класс для работы с потоком.
2) При записи в поток зачем то работа на уровне байтов. Не надо совмещать парсинг и отправку данных, заранее подготовьте пакет и разом пишите его в поток.
3) Побайтное чтение из потока тоже не вдохновляет, в первую очередь своей скоростью. И я не уверен, что вы не напутали с кодировками. У вас и 28591, и utf-8, и неявно Unicode (при добавлении символа в StringBuilder)

(2 и 3 - сделали бы пользовательскую сериализацию своего объекта)

4) Нет очистки sslStream. TcpClient вы закрываете, а его поток - нет
5) Зачем лочить WriteLocker? У вас же один поток на одного клиента. ИМХО лишняя синхронизация

1, 2, 3) Тут весь код набросан по-быстрому, так сказать PoC. Поэтому довольно нелогичный. Пакет заменить на собственно пакет с данными и скажем что-то вроде ParserStream. Кодировка везде должна быть одна Latin-1. Остальное там эксперименты )

4) ну это все туда же )
5) из-за того что сервер из другого потока может что-то сообщать клиенту, например команду на выход присунуть или сообщение.
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38468810
JustOxlamon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Arm79JustOxlamonКто готов взяться за этот кусок, если хочется денег то 90к в принципе ждут.
Arm79Но я человек занятой, и фрилансить могу не более 2-3 часов в день :-) Так что примерно месяц

Если устроят растянутые сроки, welcome

Ну или пишите сами, здесь подскажут, как правильно.

Буду думать, месяц действительно много, но сам я точно писать не буду. Так что буду искать. Ну и по-тихому писать основу для ТЗ.
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38468831
netivan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
JustOxlamon,

выложите Тз своими словами, чтобы хотя бы понимать приблизительно. Может быть там дело на выходные, а может и месяца мало :).
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38468837
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
netivanМожет быть там дело на выходные

да ну :-) Сервер под 10k клиентов должен быть обложен тестами по максимуму :-) Толку от него, если он будет постоянно падать. Там же несколько сценариев нужно предусмотреть, включая принудительный рестарт с сохранением неотправленных сообщений.
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38468858
JustOxlamon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
netivanJustOxlamon,

выложите Тз своими словами, чтобы хотя бы понимать приблизительно. Может быть там дело на выходные, а может и месяца мало :).

Звучит примерно так:

Написать TCP - сервер (теперь уже точно на C#) со следующими характеристиками:
1) Поддержка SSL (ну надо, так надо... )
2) Наиболее производительный (в мечтах 10к на одном сервере, но любое адекватное число также устроит)
3) Клиенты должны быть изолированы по возможности друг от друга. Поясню, в итоге это будет сервер где хостится много игр с одним протоколом, каждую игру будут писать разные люди со своими тараканами, поэтому из-за ошибки у одного клиента и в одной игре сервер не должен умирать и не должен убивать других игроков. В потоковом варианте, это в принципе было по умолчанию и меня сильно устраивало такой халявой.
4) Ход работы примерно такой:



1. Запускаем сервер.
2. *Внутренний менеджер загружает игровые DLL инициализирует общие данные, коннектит к бд, подгружает оттуда что надо
3. Запускается tcp-сервер на определенном порту, начинается прием.
4. Коннектится клиент, создается с ним SSL - поток
5. Клиент шлет данные, мы его авторизуем через БД*
6. Клиент выбирает игру, играет, каждый ход фиксируется в БД*
7. Клиент закрывает игру, мы подчищаем за ним.

Программировать нужно ТОЛЬКО работу с сетью (т.е. все то что без * ). Т.е. примерно то что у меня в говнозипке сидит, только это и надо. Только грамотно и с учетом требований. Понятно, что есть много дополнительных хотелок. Но они обсуждаются, фиксируются в начале работы.
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38468882
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
JustOxlamon,

Мало.

1) Как планируется обрабатывать ошибки с клиента? Может, неверный протокол. Нужно ли срубать или ожидать ввода правильных данных?
2) Как планируется защищаться от DDoS?
3) Как внутренний игровой менеджер взаимодействует с транспортным сервером? Если все в одном процессе, то надежность сервера в том числе зависит от этого менеджера. Упадет он - упадет все. Если это разные процессы, то как они будут взаимодействовать, и каков алгоритм действий при падении менеджера?
4) У вас база то выдержит обращения десятков тысяч клиентов (с учетом не одной игры)? Нет никакого кэша?
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38468902
netivan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
JustOxlamon,

теперь мне не очень понятен суть клиента и сервера. Сервер - это хрень, которая слушает TCP порты и отвечает на них в зависиомсти от клиента (видимо ответ берется из базы), или как? Один клиент - один порт, или один порт- Х клиентов (судя по примеру)... я бы вообще сделал через WCF это надо. Мне кажется в итоге и получится некий велосипед... А задача на самом деле очень интересная и как правильно заметил выше Арм, оч много можно всего накрутить. Вопрос именно в требовании.
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38468916
JustOxlamon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Arm79JustOxlamon,

Мало.

1) Как планируется обрабатывать ошибки с клиента? Может, неверный протокол. Нужно ли срубать или ожидать ввода правильных данных?
2) Как планируется защищаться от DDoS?
3) Как внутренний игровой менеджер взаимодействует с транспортным сервером? Если все в одном процессе, то надежность сервера в том числе зависит от этого менеджера. Упадет он - упадет все. Если это разные процессы, то как они будут взаимодействовать, и каков алгоритм действий при падении менеджера?
4) У вас база то выдержит обращения десятков тысяч клиентов (с учетом не одной игры)? Нет никакого кэша?

Любая ошибка клиента - отключение клиента. Клиент отлажен и априори безгрешен (я знаю-знаю, но такова политика)
От ддоса планируем лежать намертво. Это не проблема сервера.
Игровой манагер сейчас это список типов подобного толка: dictionary<string, type> при старте игры ищется игра, и создается, потом контроль передается ей, через интерфейс - OnPacket( Player pl, Paket pk, DataSource ds ); и все что внутри нее, работает как ударит моча в голову разработчика, на текущий момент при ексепшонах, падает коннект и клиент убивается - это правильно. так надо.
база держит гораздо больше, она там расшарена, кешируется, разделена по серверам и т.п. (ну хоть где-то грамотно)
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38468925
JustOxlamon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
netivanJustOxlamon,

теперь мне не очень понятен суть клиента и сервера. Сервер - это хрень, которая слушает TCP порты и отвечает на них в зависиомсти от клиента (видимо ответ берется из базы), или как? Один клиент - один порт, или один порт- Х клиентов (судя по примеру)... я бы вообще сделал через WCF это надо. Мне кажется в итоге и получится некий велосипед... А задача на самом деле очень интересная и как правильно заметил выше Арм, оч много можно всего накрутить. Вопрос именно в требовании.

Я бы тоже писал на WCF\tcp.net и был бы счастлив т.к. строгая типизация, норм трафик и ваще полная няшка. Но тут на клиент мы не влияем никак. Поэтому протокол уже есть и фиксирован.

Много клиентов, один сервер, слушает один порт.
Самих серверов может быть до 6 штук.

Действительно требуется только примерно вот это:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
interface Client{
  string Login {get;}

  void OnConnect();
  void OnDisconnect();
  void OnError( int Code );
  void OnPaсketReceived( Packet p );

  void WritePacket( Packet p );
}

interface Server{
  void Start(int Port);
  void Stop();
  
  bool ForceDisconnectUser( string Login );
  void SendPacket( string ToLogin, Packet p );
}




+/- детали НЕ усложняющие разработку. Которые будут оговорены ВНАЧАЛЕ во время написания совместного ТЗ, возможно по скайпцу. Остальное мы наговнокодим сами )
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38468929
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
JustOxlamon,

то есть:
1) Априори SSL на все без какой-либо валидации сертификата (нет защиты от подмены)
2) Нет защиты от DDOS
3) Нет обработки ошибок клиентского протокола. Чуть что - клиент, давай до свидания
4) транспортный сервер должен поддерживать плагинную структуру (хотя бы на уровне IoC)

С 4 пунктом неясно, я так и не понял, транспортный сервер и менеджер - это один процесс или несколько?
Да и интерфейс OnPacket непонятно описан.
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38468937
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
JustOxlamonСамих серверов может быть до 6 штук.

то есть всплывает еще и проблема синхронизации серверов для внутреннего менеджера :-) Или банзайный путь? Каждому транспортному серверу свой внутренний менеджер?
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38468946
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В общем, примерно понятно.

Точные сроки вам никто не скажет, мой оффер такой:

Если исходить из предположения, что будет а) нормально сформулированное ТЗ б) контактное лицо для оперативных ответов по возникающим моментам в) доступ к тестовому окружению (сервер, БД, клиенты), то сроки от 1 недели до месяца.

Предварительно: клиенты - балансировщик nginx - транспортный сервер (в виде dll, запускаемый внутренним менеджером) - БД.
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38468958
JustOxlamon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Arm79В общем, примерно понятно.

Точные сроки вам никто не скажет, мой оффер такой:

Если исходить из предположения, что будет а) нормально сформулированное ТЗ б) контактное лицо для оперативных ответов по возникающим моментам в) доступ к тестовому окружению (сервер, БД, клиенты), то сроки от 1 недели до месяца.

Предварительно: клиенты - балансировщик nginx - транспортный сервер (в виде dll, запускаемый внутренним менеджером) - БД.

Ок, ну я тогда отпишусь на мыло, что есть в контактных данных и можно начинать договариваться?
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38468972
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
JustOxlamon,

Угу.
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38468989
netivan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
JustOxlamonnetivanJustOxlamon,

теперь мне не очень понятен суть клиента и сервера. Сервер - это хрень, которая слушает TCP порты и отвечает на них в зависиомсти от клиента (видимо ответ берется из базы), или как? Один клиент - один порт, или один порт- Х клиентов (судя по примеру)... я бы вообще сделал через WCF это надо. Мне кажется в итоге и получится некий велосипед... А задача на самом деле очень интересная и как правильно заметил выше Арм, оч много можно всего накрутить. Вопрос именно в требовании.

Я бы тоже писал на WCF\tcp.net и был бы счастлив т.к. строгая типизация, норм трафик и ваще полная няшка. Но тут на клиент мы не влияем никак. Поэтому протокол уже есть и фиксирован.

Много клиентов, один сервер, слушает один порт.
Самих серверов может быть до 6 штук.

Действительно требуется только примерно вот это:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
interface Client{
  string Login {get;}

  void OnConnect();
  void OnDisconnect();
  void OnError( int Code );
  void OnPaсketReceived( Packet p );

  void WritePacket( Packet p );
}

interface Server{
  void Start(int Port);
  void Stop();
  
  bool ForceDisconnectUser( string Login );
  void SendPacket( string ToLogin, Packet p );
}




+/- детали НЕ усложняющие разработку. Которые будут оговорены ВНАЧАЛЕ во время написания совместного ТЗ, возможно по скайпцу. Остальное мы наговнокодим сами )
Сервер - обрабатывает 1 порт и передает его нужному клиенту ( опередялет по сообщению), клиент обрабатывает сообщение и отдает его обратно, так? Тогда у меня есть тоже мысли :) В "лоб" я бы не стал тут делать.
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38469210
Alex Kuznetsov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
JustOxlamon,

Насколько я понял из описаний и "реализации", ежели клиент зацепился за соединение, то тупо держит его всё время пока сам не отвалится, либо его не отвалят... - по ресурсам это чуть более чем дохрена...

Далее, все клиенты в одном Application Domain - это очень плохо. Поймал кто-нибудь необработанный Exception и практически можно завалить весь "сервер" с остальными клиентами. Отсюда вывод - работа с клиентом должна быть вынесена в отдельный AppDomain, соответственно плагинная архитектура.

Кроме того, для распределения нагрузки (если это возможно) клиентские потоки должны просто обрабатывать сообщения клиентов из очереди.
Притом в очередь они(сообщения) должны попадать и забираться асинхронно. Ну тут, как говорится всё от клиента зависит, т.е. от самого протокола.

И ещё, если по количеству соединений вроде как ограничения могут быть преодолены, то вот по количеству потоков - ну тут уж прямо и не знаю... 10К потоков одновременно... возвращаемся про "чуть более чем дохрена ресурсов"...
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38469344
JustOxlamon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Alex Kuznetsov,

Да, со всем согласен. Опыта у меня в такой разработке чуть меньше чем нету. Ранее всю черную работу делал за меня WCF\IIS.
На текущий момент договорились работать с Arm79.
Поэтому обсуждение можно пока свернуть, спасибо всем кто отписался.
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38469406
Alex Kuznetsov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
JustOxlamon,
Это то что пришло навскидку, и заодно предупредил о возможных подводных камнях...

И ещё мысли в слух: С точки зрения оптимизации нагрузки, сервис должен крутиться на машинке без всяких там IIS+SQL и т.д. , т.е. только сервис + брандмауэр. Соответственно сервис должен иметь возможность управляться извне... подумайте также и над этим...

Кстати, ещё один небольшой совет: для реализации плагинной архитектуры я бы отказался от использования интерфейсов, в пользу единого абстрактного класса, от которого будут порождаться конкретные реализации, работающие с клиентом...
Так можно больше контроля сделать...
Слой работы с базой также лучше вынести в отдельный AppDomain...

Из своего опыта: в моей реализации подобной архитектуры, обрабатывающие модули могут быть загружены и выгружены динамически, при этом сервис и остальные модули продолжают работать.
В случае сбоя одного из модулей, остальные также продолжают работать...
Всё это достигается за счёт использования различных доменов приложений.

Единственная сложность в данном случае - это межпроцессные коммуникации...

Учтите, что за неделю такие вещи сложно реализовать.
Например, у меня на реализацию с нуля нормального SMPP клиента работающего в качестве шлюза ушло порядка 3-х месяцев по 2-3 часа в день работы над проектом. Так что...

PS. Даа... интересный должен быть проект...
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38469448
JustOxlamon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Alex KuznetsovJustOxlamon,
Это то что пришло навскидку, и заодно предупредил о возможных подводных камнях...

И ещё мысли в слух: С точки зрения оптимизации нагрузки, сервис должен крутиться на машинке без всяких там IIS+SQL и т.д. , т.е. только сервис + брандмауэр. Соответственно сервис должен иметь возможность управляться извне... подумайте также и над этим...

Кстати, ещё один небольшой совет: для реализации плагинной архитектуры я бы отказался от использования интерфейсов, в пользу единого абстрактного класса, от которого будут порождаться конкретные реализации, работающие с клиентом...
Так можно больше контроля сделать...
Слой работы с базой также лучше вынести в отдельный AppDomain...

Из своего опыта: в моей реализации подобной архитектуры, обрабатывающие модули могут быть загружены и выгружены динамически, при этом сервис и остальные модули продолжают работать.
В случае сбоя одного из модулей, остальные также продолжают работать...
Всё это достигается за счёт использования различных доменов приложений.

Единственная сложность в данном случае - это межпроцессные коммуникации...

Учтите, что за неделю такие вещи сложно реализовать.
Например, у меня на реализацию с нуля нормального SMPP клиента работающего в качестве шлюза ушло порядка 3-х месяцев по 2-3 часа в день работы над проектом. Так что...

PS. Даа... интересный должен быть проект...

Да, спасибо еще раз. Я понимаю, что сроки тут без знания, что конкретно я хочу получить сложно определить. Комп где будет все крутится чистый, аки агнец невинный. 2008 r2, и все что пожелает разработчик.

А слой с БД почему надо выносить в отдельный AppDomain? есть какие-то предпосылки к этому?

И еще вопрос, как вы реализовали выгрузку модулей? У дотнета с эти проблемы. Как я понимаю только используя AppDomain?
Но тут вопрос скорости встает. В нашем проекте очень-очень-очень хотелось бы реализовать подобное. Пока решается это рестартом, из-за того что 2 версии одной длл не могут быть загружены (мы не пользовали appdomain, а просто assembly.load)
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38469451
JustOxlamon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
В идеале я бы хотел подобную архитектуру:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
//processorX_xx <- это как бы объект класса (instance) processorX

//Стартовая, чистая загрузка:

(processorA, processorB, processorC )

//Заходят клиенты, запускают свои обработчики (создают объекты классов):

cli_00: (processorA_00, processorB_00 )
cli_01: (processorA_01 )

//обнаружено обновление DLL с компонентом processorA, оно подгружается

(processorA, processorB, processorC, processorA_new )
//Клиенты продолжают работать, для них ничего не поменялось

cli_00: (processorA_00, processorB_00 )
cli_01: (processorA_01 )
//заходит еще один клиент, запускает обработчики
cli_02: (processorA_new_00 )

//выходит 0 и 1 клиент
cli_02: (processorA_new_00 )

//система обнаруживает, что processorA никто не использует и есть новая версия, можно освободить память
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38469506
netivan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alex Kuznetsov,

очереди тоже думал, но в случае, если соединение держится не вижу в них смысла особого.
Каждый плагин в домене это перебор )
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38469526
Фотография Нахлобуч
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Быть может, стоит посмотреть в сторону Node.js?
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38469752
Alex Kuznetsov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
JustOxlamon,

Покажу кусочки кода:
MyProcessorFactory
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
...
        public void AddAppProcessor(short anID, string aLibraryPath, string aClassName)
        {
            if (aPartnerName == null) return;
            if (aLibraryPath == null) return;
            if (aClassName == null) return;
            String sAppDomainName = aClassName.Replace('.', '_') + "_Domain";
            if (IsAppProcessorHere(aClassName)) return;

            try
            {
                AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
                System.Security.Policy.Evidence evidence = AppDomain.CurrentDomain.Evidence;
                AppDomain newDomain = AppDomain.CreateDomain(sAppDomainName, evidence, setup);

                MyProcessorAssembly mypa = (MyProcessorAssembly)newDomain.CreateInstanceAndUnwrap(
                                                                    typeof(MyProcessorAssembly).Assembly.FullName,
                                                                    typeof(MyProcessorAssembly).FullName);
                MyAppProcessor myapp = new MyAppProcessor();
                if (mypa.LoadAssembly(anID, aLibraryPath, aClassName))
                {
                    mypa.AddAllowedNumbers(fDBModule.GetProcessorAllowedNumbers(anID));
                    myapp.domain = newDomain;
                    myapp.processorAssembly = mypa;

                    myapp.AppProcessorName = sAppDomainName;
                    lock (oProcLock)
                    {
                        fAppProcessors.Add(myapp);
                    }
                }
                else
                {
                    System.AppDomain.Unload(newDomain);
                    newDomain = null;
                    mypa.StopAssembly();
                    mypa = null;
                    myapp = null;
                }
            }
            catch (Exception ex)
            {
                Log("Не могу загрузить процессор " + aClassName + " из " + aLibraryPath, ex);
            }
        }

...
        public bool IsAppProcessorHere(string aClassName)
        {
            if (aClassName == null) return false;
            string lName = aClassName.Replace('.', '_') + "_Domain";
            lock (oProcLock)
            {
                foreach (MyAppProcessor appd in fAppProcessors)
                    if (appd.AppProcessorName.Equals(lName))
                        return true;
            }
            return false;
        }
...

        public void StopAppProcessor(string aClassName)
        {
            if (aClassName == null) return;
            String sAppDomainName = aClassName.Replace('.', '_') + "_Domain";
            int idx = -1;
            lock (oProcLock)
            {
                idx = GetAppProcessorIndex(sAppDomainName);
                if (idx >= 0)
                {
                    fAppProcessors[idx].processorAssembly.StopAssembly();
                    try
                    {
                        System.AppDomain.Unload(fAppProcessors[idx].domain);
                    }
                    catch (Exception)
                    {

                    }
                    Thread.Sleep(1000);
                    fAppProcessors[idx].domain = null;
                    fAppProcessors[idx] = null;
                    fAppProcessors.RemoveAt(idx);
                    System.GC.Collect();
                }
            }
        }
...


MyAppProcessor
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
    public class MyAppProcessor
    {
        public AppDomain domain {get;set;}
        public MyProcessorAssembly processorAssembly { get; set; }
        public string AppProcessorName { get; set; }

        public short ID
        {
            get
            {
                return processorAssembly.ID;
            }
        }

        public string ProcessorClassName
        {
            get
            {
                return processorAssembly.ClassName;
            }
        }
    }

MyProcessorAssembly
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
    public class MyProcessorAssembly : MarshalByRefObject
    {
        private Assembly fAssembly;
        private System.Type fType = null;
        private MyProcessor processor = null;
        private short fID = 0;
        private string fClassName = "";
 
        public override object InitializeLifetimeService()
        {
            return null;
        }

        public bool LoadAssembly(MyProcessorConfig aConf)
        {
            if (aConf == null) return false;
            return LoadAssembly(aConf.ID,  aConf.LibraryPath, aConf.ProcessorClassName);
        }

        public bool LoadAssembly(short anID, string aLibraryPath, string aClassName)
        {
            try
            {
                fAssembly = Assembly.Load(AssemblyName.GetAssemblyName(aLibraryPath));
            }catch(Exception ex){
                Logger.Log("Невозможно загрузить сборку для" + aClassName, ex);
                return false;
            }

            if (fAssembly == null)
            {
                Logger.Log("Сборка " + aLibraryPath + " не загружена...");
                return false;
            }

            try
            {
                fType = fAssembly.GetType(aClassName);
            }
            catch (Exception ex1)
            {
                Logger.Log("Невозможно получить тип для" + aClassName, ex1);
                return false;
            }


            if (!fType.BaseType.Name.Equals("MyProcessor"))
            {
                Logger.Log("Указанный класс '" + aClassName + "' не является наследником от MyProcessor",System.Diagnostics.EventLogEntryType.Error);
                return false;
            }

            fID = anID;
            fClassName = aClassName;

            processor = (MyProcessor)fAssembly.CreateInstance(fType.FullName);
            processor.ID = anID;
            processor.InitProcessor();

            return true;
        }

...
        public short ID
        {
            get { return fID; }
        }

        public string ClassName
        {
            get { return fClassName; }
        }

...

        public void StopAssembly()
        {
            if (processor == null) throw new InvalidOperationException("My Processor класс не указан.");
            processor.StopProcessor();
        }
    }


MyProcessor - и есть тот абстрактный класс на основании которого созданы последующие обработчики, которые реализуют соответствующую бизнес логику.


netivan...Каждый плагин в домене это перебор ) Не думаю. Представьте себе ситуацию, когда сторонняя библиотека роняет сервис и Вам звонят клиенты у которых "денюшки" пропали... потому что по причине криворукости программистов компании А, свалился сервис в который была подгружена библиотека от компании Б...
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38469838
JustOxlamon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Alex Kuznetsov,

Огромное спасибо, я покопаю в ту сторону, конечно из-за реалтаймовского характера приложения, смущает проблема скорости.
Вы обошлись тут без интерфейсов, у нас тоже базовый абстрактный класс. По-моему это супер.
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38469864
Alex Kuznetsov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
JustOxlamonAlex Kuznetsov,

Огромное спасибо, я покопаю в ту сторону, конечно из-за реалтаймовского характера приложения, смущает проблема скорости.
Вы обошлись тут без интерфейсов, у нас тоже базовый абстрактный класс. По-моему это супер.
А что скорость - она от скорости обработки запроса зависит...
У меня под тестовой нагрузкой сервис за одну секунду обрабатывал до 512 сообщений, а это, принятие + парсинг + уложить в базу + обработать + отослать ответ + уложить ответ в базу...
И это при том, что всё крутилось в виртуалке с ХР, с установленной в ней студией, SQL сервером, запущенным IIS, сервис был с отладочной инфой, трейсингом и т.д., памяти было выделено под виртуалку всего 3 гига... пакеты шли пачкой по 512 сообщений.
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38469934
netivan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alex KuznetsovJustOxlamonAlex Kuznetsov,

Огромное спасибо, я покопаю в ту сторону, конечно из-за реалтаймовского характера приложения, смущает проблема скорости.
Вы обошлись тут без интерфейсов, у нас тоже базовый абстрактный класс. По-моему это супер.
А что скорость - она от скорости обработки запроса зависит...
У меня под тестовой нагрузкой сервис за одну секунду обрабатывал до 512 сообщений, а это, принятие + парсинг + уложить в базу + обработать + отослать ответ + уложить ответ в базу...
И это при том, что всё крутилось в виртуалке с ХР, с установленной в ней студией, SQL сервером, запущенным IIS, сервис был с отладочной инфой, трейсингом и т.д., памяти было выделено под виртуалку всего 3 гига... пакеты шли пачкой по 512 сообщений.
512 в секнду в записью в базу? Да вы монстр. По поводу доменов наверное согласен, если считать что плагины пишет другой человек, то да.
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38470023
Alex Kuznetsov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
netivan512 в секнду в записью в базу? Да вы монстр... Ну почему сразу монстр? Обычная очередь, плюс поток, плюс пулл соединений... Всё нормально...
В данном случае задача сервиса была дать как можно быстрый ответ SMPP серверу о том, что пакет получен,
распарсен и принят в обработку, а когда оно именно в базу попадёт - это уже вопрос отдельный
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38470047
netivan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alex Kuznetsovnetivan512 в секнду в записью в базу? Да вы монстр... Ну почему сразу монстр? Обычная очередь, плюс поток, плюс пулл соединений... Всё нормально...
В данном случае задача сервиса была дать как можно быстрый ответ SMPP серверу о том, что пакет получен,
распарсен и принят в обработку, а когда оно именно в базу попадёт - это уже вопрос отдельный
очередь, так и писали бы : отправилась "задача" на запись в базу :)
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38470057
Alex Kuznetsov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
netivan...
очередь, так и писали бы : отправилась "задача" на запись в базу :) Ну можно и так сказать...
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
TCP\SSL-Server на C#
    #38812717
Фотография des1roer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
народ подскажите в чем трабла
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
   internal class DoWork
        {
            string SERV, MES, ParseGlob;
            private bool doWork;
            private System.Threading.Thread thread;
            readonly EventWaitHandle wh = new AutoResetEvent(false);
            int IdCom, Port, ansLen;
            Regex rxNums = new Regex(@"^\d+$");

            internal DoWork(String server, String message, Int32 port, Int32 idcom, String Parse, Int32 dlina)
            {
                SERV = server;
                MES = message;
                Port = port;
                IdCom = idcom;
                ansLen = dlina;
                if (Parse != "")
                    ParseGlob = Parse;
            }
            public void ThreadStart()
            {
                doWork = true;
                thread = new Thread(Execute);
                thread.Start();


            }
            public void ThreadStop()
            {
                doWork = false;
                wh.Set();

            }
            void Execute()
            {
                try
                {
                    if (doWork)
                        Connect(SERV, MES, Port);

                }
                catch (Exception msg)
                {
                    logger.Trace("Execute() " + msg);
                    return;
                }
            }

            public void Connect(String server, String message, Int32 port)
            {
                try
                {
                    // Create a TcpClient.
                    // Note, for this client to work you need to have a TcpServer 
                    // connected to the same address as specified by the server, port
                    // combination.

                    // 
                    TcpClient client = new TcpClient(server, port);

                    // Translate the passed message into ASCII and store it as a Byte array.
                    Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);

                    // Get a client stream for reading and writing.
                    //  Stream stream = client.GetStream();

                    NetworkStream stream = client.GetStream();

                    // Send the message to the connected TcpServer. 
                    stream.Write(data, 0, data.Length);

                    //   logger.Trace("Sent: {0}", message);
                    if (list[10] == "1")
                    {
                        logger.Trace("Sent: {0}", message);
                    }
                    doWork = false;
                    // Receive the TcpServer.response.
                    //  Thread.Sleep(2000);   
                    // Buffer to store the response bytes.
                    data = new Byte[256];

                    // String to store the response ASCII representation.
                    String responseData = String.Empty;

                    // Read the first batch of the TcpServer response bytes.
                    Int32 bytes = stream.Read(data, 0, data.Length);
                    responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);

                    if (list[10] == "1")
                    {
                        logger.Trace("port_DataReceived " + responseData);
                    }


                }
                catch (ArgumentNullException e)
                {
                    logger.Trace("ArgumentNullException: {0}", e);
                    return;
                }
                catch (SocketException e)
                {
                    logger.Trace("SocketException: {0}", e);
                    Thread.Sleep(1000); 
                    return;
                }
            }
            public bool ThreadState()
            {
                if (doWork)
                    return true;
                else return false;
            }
        }


опрашивает первые 3 раза (на одном порту 4 прибора у них разные коды) а потом пишет Trace|SocketException: {0}
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38812747
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
а кто будет делать NetworkStream.Dispose и TcpClient.Close ??
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38812749
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
des1roer
Код: c#
1.
2.
3.
4.
5.
6.
public bool ThreadState()
            {
                if (doWork)
                    return true;
                else return false;
            }


Вот это шедевр.

public bool ThreadState { get { return doWork; } }
...
Рейтинг: 0 / 0
TCP\SSL-Server на C#
    #38812759
Arm79
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
des1roer
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
            public void ThreadStart()
            {
                doWork = true;
                thread = new Thread(Execute);
                thread.Start();


            }
            public void ThreadStop()
            {
                doWork = false;
                wh.Set();

            }


Так делать можно, но не нужно, из старого кода:
отдельный тред
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
using System;
using System.Threading;

namespace Threads
{
    /// <summary>
    /// Аргументы для события "Старт потока"
    /// </summary>
    public sealed class StartArgs : EventArgs
    {
        #region .ctor

        public StartArgs(bool wasStarted)
        {
            WasStopped = wasStarted;
        }

        #endregion

        /// <summary>
        /// Состояние потока до вызова метода Start()
        /// </summary>
        public bool WasStopped { get; private set; }
    }

    /// <summary>
    /// Аргументы для события "Останов потока"
    /// </summary>
    public sealed class StopArgs : EventArgs
    {
        #region .ctor

        public StopArgs(bool wasStarted, bool exitByTimeout)
        {
            WasStarted = wasStarted;
            IsExitByTimeout = exitByTimeout;
        }

        #endregion

        /// <summary>
        /// Состояние потока до вызова метода Stop()
        /// </summary>
        public bool WasStarted { get; private set; }

        /// <summary>
        /// Флаг прерывания потока исполнения по таймауту
        /// </summary>
        public bool IsExitByTimeout { get; private set; }
    }

    /// <summary>
    /// Шаблон для выполнения метода в отдельном потоке с дополнительным функционалом управления и мониторинга
    /// </summary>
    /// <remarks>Потомки должны быть сериализуемыми</remarks>
    public abstract class ThreadWorkerTemplate : DisposableTemplate
    {
        #region Private

        private int _threadFlag;
        private readonly Thread _thread;

        /// <summary>
        /// Обработчик потока
        /// </summary>
        private void ThreadHandler()
        {
            // Здесь реализуем пользовательскую задержку, вместо Thread.Sleep(), так как она позволит отреагировать на команду завершения работы
            DateTime lastExecuted = DateTime.MinValue;
            Func<bool> isAllowed =
                () =>
                {
                    DateTime now = DateTime.Now;
                    bool result = IsNothingDelay() || IsDelaySpended(now, lastExecuted);

                    if (result)
                        lastExecuted = now;

                    // Допустим и 0, то тогда в диспетчере будет показываться 100% загрузка. При этом приложение будет отзываться
                    // Значение 1 задает на самом деле интервал 10-15, то есть менее минимального квантификатора задержки быть не может
                    if (IterationTimespan != -1)
                        Thread.Sleep(1);

                    return result;
                };

            // в цикле осуществляется вызов бизнес-функции 
            while (Interlocked.CompareExchange(ref _threadFlag, 0, 0) == 1)
            {
                if (isAllowed())
                    WorkFunction();
            }
        }

        /// <summary>
        /// Проверка, прошел ли минимальный интервал времени между итерациями
        /// </summary>
        /// <param name="now"></param>
        /// <param name="lastExecuted"></param>
        /// <returns></returns>
        /// <remarks>задержка не менее заданного интервала времени</remarks>
        private bool IsDelaySpended(DateTime now, DateTime lastExecuted)
        {
            return (now > lastExecuted) // учет коррекции времени ntp-сервисом
                   &&
                   (now - lastExecuted).TotalMilliseconds > IterationTimespan;
        }

        /// <summary>
        /// Проверка на наличие задержки
        /// </summary>
        /// <remarks>-1 означает отсутствие какой-либо задержки</remarks>
        private bool IsNothingDelay()
        {
            return IterationTimespan == -1;
        }

        #endregion

        #region .ctor/dispose/finalize

        protected ThreadWorkerTemplate(int timeout) : this(timeout, new TimeSpan(0, 0, 0, 10)) { }

        protected ThreadWorkerTemplate(int timeout, TimeSpan joinTimeout, ApartmentState apartmentState = ApartmentState.Unknown)
        {
            IterationTimespan = timeout;
            JoinTimeout = joinTimeout;

            _threadFlag = 0;
            _thread = new Thread(ThreadHandler);
            _thread.SetApartmentState(apartmentState);
        }

        #endregion

        #region Invocators

        private void InvokeOnStart(StartArgs e)
        {
            EventHandler<StartArgs> handler = OnStart;
            if (handler != null) handler(this, e);
        }

        private void InvokeOnStop(StopArgs e)
        {
            EventHandler<StopArgs> handler = OnStop;
            if (handler != null) handler(this, e);
        }

        #endregion

        #region Events

        /// <summary>
        /// Событие, возникающее при старте обработки метода
        /// </summary>
        public event EventHandler<StartArgs> OnStart;

        /// <summary>
        /// Событие, возникающее при останове обработки метода
        /// </summary>
        public event EventHandler<StopArgs> OnStop;

        #endregion

        #region Management

        /// <summary>
        /// Старт запуска метода в отдельном потоке
        /// </summary>
        public void Start()
        {
            bool oldState = !IsStarted;

            // стартуем с одновременным измененем флага
            if (Interlocked.CompareExchange(ref _threadFlag, 1, 0) == 0)
                _thread.Start();

            InvokeOnStart(new StartArgs(oldState));
        }

        /// <summary>
        /// Останов обработки метода в отдельном потоке
        /// </summary>
        public void Stop()
        {
            bool oldState = IsStarted;
            bool exitByTimeout = false;

            // стопаем с одновременным измененем флага
            if (Interlocked.CompareExchange(ref _threadFlag, 0, 1) == 1)
                exitByTimeout = !_thread.Join(JoinTimeout);

            InvokeOnStop(new StopArgs(oldState, exitByTimeout));
        }

        #endregion

        #region For overrite

        /// <summary>
        /// Метод, который должен исполняться в отдельном потоке.
        /// </summary>
        protected abstract void WorkFunction();

        #endregion

        #region Properties

        /// <summary>
        /// Флаг, показывающий текущее состояние ThreadWorker (запущен или нет)
        /// </summary>
        public bool IsStarted
        {
            get { return Interlocked.CompareExchange(ref _threadFlag, 0, 0) == 1; }
        }

        /// <summary>
        /// Интервал времени, после которого прекращается номмальное завершение потока испольнения метода <see cref="WorkFunction"/>
        /// </summary>
        public TimeSpan JoinTimeout { get; private set; }

        /// <summary>
        /// Минимальный интервал времени между вызовами метода <see cref="WorkFunction"/>
        /// </summary>
        public int IterationTimespan { get; private set; }

        #endregion
    }
}

...
Рейтинг: 0 / 0
47 сообщений из 47, показаны все 2 страниц
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / TCP\SSL-Server на C#
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]