Как стать автором
Обновить

Комментарии 72

хм, без обид, но помнится что это было заданием на лабораторную работу для второго курса. =)

Впрочем, если это первая статья в цикле, то задел хороший.
Ну, у нас на втором курсе в дельфях кнопочки на форму кидать учились. Так что тут я вам завидую :-) А на эту тему планирую еще одну статью, про конфиги и CGI.
мне мало верится, что такому учат на втором курсе, ибо на «чисто программерских» специальностях на втором курсе обычно пилят ещё чистые С (и это ещё в лучшем случае), а на около программерских вообще таких вещей не изучают на лабах (максимум синтаксис и основные конструкции), всётаки http-server это достаточно частный пример. Где вы учились?
ХАИ, заочное отделение:
1-2 курсы: паскаль, основы
3 курс: ооп в делфи
4 курс: структуры данных, базы данных
5 курс: компиляторы, основы ИИ.

как то так…
Аналогичная ситуация, ХНУРЭ.
1-2 курсы: с++, основы
МГТУ «Станкин» специальность «информационные системы»
1 семестр — паскаль
2 семестр — делфи, основы ООП
3 семестр — Плюсы
4 семестр — Шарп в курсе по программированию и сабж в курсе, дай бог память, вроде сетей ЭВМ и телекоммуникаций.
Боже мой, наши люди.

Сейчас там не преподают делфи и плюсы больше, нет средств. Сразу после паскаля шарп.
МГГУ «Горный» специальность САПР(системы автоматизированного проектирования)
1 курс — Паскаль, Делфи
2 курс — Си++
3 курс:
— 1 семестр — СУБД: MS SQL Server, GMax, Blender
— 2 семестр — MS Visual Studio и мышеводство на формах с использованием ADO.NET, OpenGL
4 курс — пролог, псевдо-веб технологии, диплом
ИТМО, факультет информационных технологий и программирования.
мы это (правда на джаве) недавно проходили.

1 курс. паскаль, плюсы
2 курс. джава, ассемблер.
БГУИР, ФИТУ — Искусственный интеллект
1. С/C++: простенькие алгоритмы
2. C++: WinApi, Java: OOP
3. Операционные системы, сетевые протоколы, компиляторы, базы данных
4. Обработка изображений, параллельная обработка данных
5. Нейронные сети
Донецк, Донну, кафедра компьютерных технологий
1 курс — паскаль
2 курс — плюсы, основы ООП на плюсах, WinAPI, структуры данных, базы данных
3 курс — C#. Лаба по сетям на шарпе заключалась в получении бд с сервера и отображении на сервере. Почти сабж
4 курс — джава

Но вот если бы мне сейчас надо было писать ту лабу, топик бы очень даже помог.
ВМиК МГУ, прикладная математика и информатика
1 семестр — паскаль (и лекции по алгоритмам)
2 семестр — ассемблер (архитектура ЭВМ)
3 семестр — Си (операционные системы)
4 семестр — С++ (формальные грамматики и языки)
Потом разделение по кафедрам. Мы учили Яву, программистские кафедры — функциональные языки, Ява, БД и пр.
Вообще, по-моему, было бы интересно в отдельной теме собрать информацию, кто что учил в универе. А потом свести всё в единую таблицу, и по программированию, и другие дисциплины.
Нам было бы любопытно, абитуриентам полезно.
Прикладные математические кафедры (2 поток) учат в основном Матлаб, хотя делать почти все практические вычислительные задачи разрешается в любом языке (включая VBA+Excel), главное, чтобы работало.

Ну и да, на 3 курсе, все в обязательном порядке изучают БД (реляционные, нереляционные, алгоритмы, соотв. математика) и основы SQL.
Да, забыл, еще на 3 курсе все изучают машинную графику и сдают практическую работу в виде демосцены на OpenGL/DirectX с использованием всяких эффектов, шейдеров и т.д.
Политех (Казахстан), САПР заочное (псевдо дистанционное) отделение, сокращенное обучение после колледжа (родственная специальность).
1 курс — C++/Pascal.
2 курс — БД, Delphi.
3 курс — Есть лабораторные выполняемые в Pascal!!!
диплом.

Как видите у нас ни Java, ни шарпом не пахнет.
Самое веселое то, что я просил написать курсовые/лабы на C#, на что мне ответили отказом, опираясь якобы на «программу», в которой ведется весь учет курса.

Всегда злило обучение, ни колледж, ни универ не дают реальных навыков которые требуются в работе, действительно, если хочешь чему-то научиться, то уж извини, сам.
НЛО прилетело и опубликовало эту надпись здесь

Семафоры, мьютексы, критические секции это база многопоточного программирования, как минимум под виндой, а вовсе не C# (

А где ж бенчмарки? Где потребление ресурсов на разных нагрузках?
Нет, я понимаю что цель — не быстродействие, но хочется знать насколько производительно это решение за 20 минут.
Проверил через wbox. Отладочная сборка, через ThreadPool (8 потоков). В спокойном режиме жрет 2,7 метра памяти. При 25 клиентах жрет 3,3 метра и 2% процессора. При 100 клиентах — 3,6 метра и до 15%. При отключении клиента может выдавать ошибку (но не завершаться полностью). Ошибка связана с отсутствием в коде лишних блоков try/catch, которые я не стал писать для простоты (достаточно будет экранировать new Client((TcpClient)StateInfo); в ClientThread, пусть это будет не совсем логически верно).
2% какого процессора-то?
HttpListener вообще по производительности получится быстрее TcpListener, так как использует напрямую драйвер ОС http.sys, поэтому бенчмарки ничего бы путного не показали
(разумеется, имел ввиду быстрее чем реализация веб-сервера с помощью TcpListener)
О ужас! HTTP в ядре??
Вы ещё весь TCP-стек в юзерленд вынести предложите. Такой же протокол как и все остальные. В ядре ему самое место, смысл данные туда-сюда гонять, если их можно в одном месте обработать?
Вы еще предложите все программы в ядре запускать. Ведь зачем же данные туда-сюда гонять))
Глупость сказали. Вы, вероятнее всего, никогда не писали высоконагруженный софт. Там идёт экономия на каждом вызове к ядру, ибо любой обмен данными с ядром — это немаленький такой оверхед, который жрёт процессорное время со страшной силой. Недавно вот писали, что линуксу сейчас прикручивают механизм группировки сисколов, чтобы несколько вызовов шло ядру в одном пакете. Никогда не задумывались, зачем?
И какой смысл делать n запросов на чтение из сокета (в котором данные появляются по кускам), если можно одним вытащить уже распарсенный http-запрос?
Это пример того как НЕ надо писать код. Вы не используете IOCP (следствие — ужасная масштабируемость), а для HTTP вообще есть специальное API.
Про IOCP я знаю, но оно не входит в .NET (по меньшей мере, те статьи на эту тему, которые я находил в интернете, используют неуправляемый код). Про HttpListener я написал в первом абзаце. Целью статьи было написать простой HTTP-сервер на .NET. За основу брался еще более простой код с RSDN.
Ну здрасьте, а BeginAccept, BeginSend, BeginReceive по вашему как работают, если не через IOCP? Там самый что ни на есть IOCP!

А что касается форума РСДН: Исходники, то там много хлама.
Пардон, вот этого не знал. Спасибо, учту.
«Про IOCP я знаю, но оно не входит в .NET (по меньшей мере, те статьи на эту тему, которые я находил в интернете, используют неуправляемый код). „
И это в то время, как в последней рихтеровской CLR via C# мало того, что рассказано про IOCP, так еще и есть пример кода… сервера (правда, будем честными, пайпового) под .net.
Как-то финализатор класса Server нелепо смотрится. Здесь разумнее реализовать IDisposable, а TcpListener должен сам остановиться, когда его GC найдет.
Я бы сказал, что финализатор не только нелепо смотрится, но это и показательный пример того, как делать не надо. И за бездумное использование финализаторов, считаю, нужно устраивать публичную порку. :)
Объясню почему. Тот же TcpListener.Stop метод может легко кинуть SocketException. А что это значит для нас? Это значит, что возникни это исключение в финализаторе и вся аппликация упадет, причем так, что мы даже не узнаем, что и где случилось.
Спасибо, учту на будущее :-)
и вся аппликация упадет

Аппликация — вырезание и наклеивание (нашивание) фигурок, узоров или целых картин из кусочков бумаги, ткани, кожи, растительных и прочих материалов на материал-основу (фон).
Правильно, но тут даже если мы перехватим все исключения — ничего путного не выйдет :)
Очистка объектов с финализаторами производится за 2 сборки мусора, поэтому у объекта больше шансов попасть во 2-е поколение, которое собирается реже. GC может работать в несколько потоков (как например при фоновой сборке в .net 4, когда объекты поколений 0-1 и 2 собираются в разных потоках), поэтому Listener != null не спасет, надо ставить мьютекс, что опять же чревато (к управляемым ссылками тут обращаться вообще не стоит). Наконец объект TcpListener имеет свой финализатор, т.е. этот наш ~Server не делает ровным счетом ничего, кроме как создает проблемы :)
О финализаторах лучше забыть как о страшном сне до тех пор, пока не понадобится работать с неуправляемыми ресурсами. А сама статья неплохая, про основы сокетов и потоков :)
Меня больше беспокоит, что ссылка на объект Server нигде не сохраняется. Не умрет ли он в релизной сборке? Кстати, в конкретном примере финализатор будет вызван только при остановке приложения и исключение в нем самому приложению не повредит. Ну а IDisposable нужен только там, где управление освобождением ресурсов осуществляется (или подразумевается, что будет осуществляться) вручную.
Не умрёт. Часто использую конструкцию new Thread(MyProc).Start(); и никто от этого не умер.
Ммм… немного некорректный пример, так как новый поток сам является источником корней для графа объектов и его-то GC собирать не будет, но ответ про «не умрет» все равно верный, так как, по сути, основной поток навсегда замирает в конструкторе объекта.
Вы не говорили про GC. Вы говорили про релизную сборку. Работа компилятора по вырезанию лишнего хлама и работа GC — несколько разные вещи.
Простите, под смертью я подразумевал удаление посредством GC из-за отсутствия корня. В дебаге этого не происходит, а в релизе — обычное дело.
Не говоря уже о том, что в финализаторе нельзя обращаться к другим финализируемым объектам, так как порядок вызова финализаторов не определён: «Specifically, you must know that any code you call from within a Finalize method does not use any other object that could have already been finalized.» © Richter

И вообще: «If you’re familiar with C++, you’ll notice that the special syntax C# requires for defining a Finalize method looks just like the syntax you’d use to define a C++ destructor. In fact, the C# Programming Language Specification calls this method a destructor. However, a Finalize method doesn’t work like an unmanaged C++ destructor at all, and this has caused a great deal of confusion for developers migrating from one language to another.
The problem is that developers mistakenly believe that using the C# destructor syntax means that the type’s objects will be deterministically destructed, just as they would be in C++. However, the CLR doesn’t support deterministic destruction, preventing C# from providing this mechanism.» © Richter
НЛО прилетело и опубликовало эту надпись здесь
Можно уточнить что значит значок "~" перед именем Server?
Вот и выросло поколение людей, которые не знают, что такое "~"…
Я никого не защищаю, конечно, стыдно не знать, что такое деструктор (хотя, если человек никогда не был связан с программированием, то почему бы и нет?), но, судя по профилям, это «поколение» вас старше на 5 лет.
Да и степень стыдобы в данном случае — вопрос обсуждаемый. В дот нете часто лучше не знать, что ~ — это деструктор.
Ну если человек не связан с программированием, то что он забыл в топике, где по сути кроме кода и нету ничего? А то, что на 5 лет старше, так это вдвойне грустно.
Кому тема mini-серверов на .Net интересна, рекомендую посмотреть Cassini: en.wikipedia.org/wiki/Cassini_Web_Server Он не на много сложнее, но поддерживает ASP.Net (не только статика).
Вообще говоря многопоточные сервера — зло. Есть же дотнете асинхронщина для неблокирующей работы с сокетами.
Если делать простые вещи с упором на производительность — то да. Если что-то сложное — умаешься так писать.
Если вынести логику в схему «запрос-ответ» с сохранением состояний а ля сессия, а работу с пакетами перенести на отдельный уровень, то всё ок. Получаем событийную модель.
Останутся еще обращения к базе и прочим файлам, которые блокируют. Через это придется программу разрезать на куски, пихать куда-то временный стейт и все такое. Такой режим в ASP.net, кстати, есть. Но что-то более-менее сложное писать на этом умаешься.
С сишарповским-то синтаксисом замыканий? Наплодил колбэков и поехали. Тем более что сейчас соорудили ключевое слово async.
С точки зрения программирования: делать в конструкторе бесконечный цикл и закладывать логику в деструктор (это акутально для .NET) как-то нехорошо, мне кажется. Даже в рамках демонстрационного примера.
Сам интересный для меня вопрос: а что такого специфически c#-ного тут?

Это не «сервер на c#, это „сервер на clr“.

Ну и да, выше правильно пишут, в нем столько ошибок, что на нем можно делать демонстрации „как не надо делать“.
        // В бесконечном цикле
        while (true)


писать комментарии хорошо, но такие абсолютно бесполезны.
Пул потоков надо делать изначально расширяемым. Лучше медленно обслужить все запросы, чем вообще не обслужить половину.
Он расширяемый. Просто когда потоков больше лимита, они начинают создаваться не чаще чем раз в полсекунды вроде. Да и лимит там по-умолчанию вроде больше чем 8, что-то типа по 20 на ядро.
Называть локальные и приватные переменные с большой буквы — это некомильфо.
Обращаться к управляемым объектам в деструкторе — просто нельзя.
Если вы уже пишите комментарии, то для классов и методов лучше использовать xml-образные.
Вы извините, если это выглядит как то, что я придираюсь, просто при написании коммерческого кода Вас за это могут больно пнуть.
Ощущение, что статья устарела лет эдак на N.
Какие деструкторы (IDisposable!), какой Thread.Start (TPL!)…
Написать что ли статью «многопоточный веб-сервер на PHP»? :)
А почему Вы просто не воспользовались встроенным классом HttpListener?
Пропустил первый абзац =(
Как поделка для здачи преподу сгодится. А так нужно исспользовать WCF и не плодить велосипеды.
— конкатенацию при помощи "+";
— магические числа в коде (даже степени двойки);
— "", когда надо писать string.Empty (или ничего не писать, если объявление, всё равно инициализация по умолчанию);

Люблю:
— следовать общепринятым стандартам наименования;
— использовать Path для конкатенации путей;
— использовать var
— использовать using, чтобы не забыть закрыть stream

Сугубо ихмо. Ну а статья в целом познавательна для незнакомых с темой.
С каких это пор default(string) == string.Empty? Всегда null было.
Не равно, конечно. Присваивать в начале string.Empty или нет нужно в зависимости от того, как дальше будет использоваться переменная.

У меня смутное ощущение, что то же самое на голом WinSock будет не сложнее

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации