LXF98:Mono
Belogorie (обсуждение | вклад) |
Lockal (обсуждение | вклад) м (Шаблон:Цикл/Mono AWB) |
||
(не показаны 6 промежуточных версий 2 участников) | |||
Строка 1: | Строка 1: | ||
+ | {{Цикл/Mono}} | ||
+ | |||
==<font color=darkred>Mono:</font> Назад в Unix== | ==<font color=darkred>Mono:</font> Назад в Unix== | ||
Строка 11: | Строка 13: | ||
===Posix и вы=== | ===Posix и вы=== | ||
− | Имеется два типа людей, в основном использующих Posix: конечные пользователи и разработчики. Значит, практически все! Рассмотрим каждый тип отдельно, начав с пользователя. Да, я помню свои слова, что конечный пользователь игнорирует Posix, но это не совсем верно – фактически, вы используете преимущества инструментов и интерфейсов Posix при каждом обращении к командной строке. Видите ли, Posix заправляет едва ли не всем, что даруют Unix-подобные операционные системы – как работает ваша командная строка, есть ли инструменты типа awk и компиляторов, как происходит взаимодействие программ через каналы. Пусть даже конечные пользователи ничего не знают и знать не хотят о Posix, они обязательно опираются на его набор функций! Что касается разработчиков, то любой из пишущих код на С должен работать с одним из многих интерфейсов ядра и вызовами стандартной библиотеки С, входящими в Posix, и эти функции – например, malloc, system, printf, fopen и другие – доступны везде, куда ни сунься. | + | Имеется два типа людей, в основном использующих Posix: конечные пользователи и разработчики. Значит, практически все! Рассмотрим каждый тип отдельно, начав с пользователя. Да, я помню свои слова, что конечный пользователь игнорирует Posix, но это не совсем верно – фактически, вы используете преимущества инструментов и интерфейсов Posix при каждом обращении к командной строке. Видите ли, Posix заправляет едва ли не всем, что даруют Unix-подобные операционные системы – как работает ваша командная строка, есть ли инструменты типа awk и компиляторов, как происходит взаимодействие программ через каналы. Пусть даже конечные пользователи ничего не знают и знать не хотят о Posix, они обязательно опираются на его набор функций! Что касается разработчиков, то любой из пишущих код на С должен работать с одним из многих интерфейсов ядра и вызовами стандартной библиотеки С, входящими в Posix, и эти функции – например, <font color=darkred>malloc</font>, <font color=darkred>system</font>, <font color=darkred>printf</font>, <font color=darkred>fopen</font> и другие – доступны везде, куда ни сунься. |
Это ставит нас перед вопросом: «Какой прок в использовании Posix?» Общеизвестно, что все системные вызовы Posix скопированы в стандарте среды .NET, с использованием управляемых эквивалентов: вы можете читать и записывать файлы, работать со строками, открывать сокеты, читать данные файловой системы и так далее, не беспокоясь о распределении памяти, потому что .NET освободит все, когда сработает сборщик мусора. Но использование версий Posix дает некоторые преимущества: | Это ставит нас перед вопросом: «Какой прок в использовании Posix?» Общеизвестно, что все системные вызовы Posix скопированы в стандарте среды .NET, с использованием управляемых эквивалентов: вы можете читать и записывать файлы, работать со строками, открывать сокеты, читать данные файловой системы и так далее, не беспокоясь о распределении памяти, потому что .NET освободит все, когда сработает сборщик мусора. Но использование версий Posix дает некоторые преимущества: | ||
− | + | # Унаследованный код очень легко портировать. Вы можете взять код на C и запросто перенести его на C#, затем, при добавлении новых функций, добавить расширенную функциональность, присущую C#. | |
− | + | # В том же русле: для C-программистов вполне очевидно, что делает код C# Posix, а это облегчает изучение и сопровождение. | |
− | + | # Вы можете использовать преимущества специфичной для Posix функциональности. Например, чтение данных из файла '''/etc/passwd''' в обычном .NET коде необходимо делать вручную, а с использованием инструментов Posix это раз плюнуть. | |
− | + | ||
− | + | ||
Итак, использование Posix не лишено преимуществ, но вдобавок имеется одно большое неудобство: львиная доля Posix работает с указателями. | Итак, использование Posix не лишено преимуществ, но вдобавок имеется одно большое неудобство: львиная доля Posix работает с указателями. | ||
Строка 27: | Строка 27: | ||
===Базируемся на Stdlib=== | ===Базируемся на Stdlib=== | ||
− | Имеется три компонента для поддержки Unix в Mono: Mono.Posix, Mono.Unix и Mono.Unix.Native. Два последних отличаются лишь тем, что Mono.Unix – это небольшая обертка для Mono.Unix.Native, но вы можете использовать ту, где вам комфортнее. | + | Имеется три компонента для поддержки Unix в Mono: <font color=darkred>Mono.Posix</font>, <font color=darkred>Mono.Unix</font> и <font color=darkred>Mono.Unix.Native</font>. Два последних отличаются лишь тем, что <font color=darkred>Mono.Unix</font> – это небольшая обертка для <font color=darkred>Mono.Unix.Native</font>, но вы можете использовать ту, где вам комфортнее. |
− | + | ||
− | + | ||
+ | Начнем с простого: создадим новое решение под названием <font color=darkred>Monix</font>, затем изменим его код '''Main.cs''' так: | ||
+ | <source lang="c"> | ||
using Mono.Posix; | using Mono.Posix; | ||
using Mono.Unix; | using Mono.Unix; | ||
Строка 39: | Строка 39: | ||
class Monix { | class Monix { | ||
public static void Main(string[] args) { | public static void Main(string[] args) { | ||
− | Stdlib.system( | + | Stdlib.system("ls"); |
} | } | ||
} | } | ||
} | } | ||
+ | </source> | ||
+ | Этот простой код – основа для всех дальнейших: будем изменять только строку <font color=darkred>Stdlib.system()</font> да добавлять кое-какие кусочки. | ||
+ | Проверьте наличие Mono.Posix и добавьте ссылку на него в проект. В нашем первом методе мы воспользуемся классом <font color=darkred>Stdlib</font> для вызова <font color=darkred>system()</font>. Класс <font color=darkred>Stdlib</font> содержит, в основном, статические методы, то есть вам не нужно создавать объект <font color=darkred>Stdlib</font> для вызова этих методов. Метод <font color=darkred>system()</font> (следите за регистром <font color=darkred>s</font> – он нижний: сейчас мы в стране С!) исполняет любую команду на локальной машине, словно он был введен в командной строке. Для нашего примера это означает запуск ls, поэтому программа выведет список каталогов, как если бы вы сами запустили «ls». | ||
− | + | После ввода <font color=darkred>Stdlib.system()</font>, MonoDevelop должна вывести информацию о параметрах метода <font color=darkred>system()</font>, и вы увидите, что он принимает строки C#. В этом месте разработчики Mono адаптировали библиотеку вызовов C для лучшей совместимости с программированием .NET – обычно, в терминах С, <font color=darkred>system()</font> получает <font color=darkred>const char*</font>, так что использование строк более изящно! | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | Этот переход существует лишь в некоторых методах. Например, <font color=darkred>printf()</font> также дружественен к .NET, поэтому вы можете писать код вроде этого: | |
− | + | <source lang="c"> | |
− | Этот переход существует лишь в некоторых методах. Например, printf() также дружественен к .NET, поэтому вы можете писать код вроде этого: | + | Stdlib.printf("Hello, %s!\n", "world"); |
− | + | Stdlib.printf(string.Format("Hello, {0}!\n", "world")); | |
− | Stdlib.printf( | + | </source> |
− | Stdlib.printf(string.Format( | + | С другой стороны, методы <font color=darkred>fopen()</font>, <font color=darkred>fwrite()</font> и <font color=darkred>fclose()</font> для работы с файлами требуют указателей. В C# указатели известны как <font color=darkred>IntPtr</font>, потому что это представление указателя в целочисленном типе данных. Эти <font color=darkred>IntPtr</font>'ы могут восприниматься как данные с неизвестной структурой: их нельзя прочесть без использования специфичных для этих данных методов. Например, файлы открываются так: |
− | + | <source lang="c"> | |
− | С другой стороны, методы fopen(), fwrite() и fclose() для работы с файлами требуют указателей. В C# указатели известны как IntPtr, потому что это представление указателя в целочисленном типе данных. Эти | + | IntPtr foo = Stdlib.fopen("file.txt", "w"); |
− | + | </source> | |
− | IntPtr foo = Stdlib.fopen( | + | Но вы не можете читать или записывать с этого файлового дескриптора без других методов <font color=darkred>Stdlib. foo IntPtr</font> – всего лишь дескриптор данных, и сам по себе бесполезен. На самом деле, это даже небезопасно: любая память, присвоенная указателю, недоступна сборщику мусора Mono, и необходимо освобождать ее вручную, не то образуется утечка [memory leak]. Вы можете выполнить запись в этот файл, затем закрыть его так: |
− | + | <source lang="c"> | |
− | Но вы не можете читать или записывать с этого файлового дескриптора без других методов Stdlib. foo IntPtr – всего лишь дескриптор данных, и сам по себе бесполезен. На самом деле, это даже небезопасно: любая память, присвоенная указателю, недоступна сборщику мусора Mono, и необходимо освобождать ее вручную, не то образуется утечка [memory leak]. Вы можете выполнить запись в этот файл, затем закрыть его так: | + | Stdlib.fwrite(Encoding.ASCII.GetBytes("Hello, world!"), foo); |
− | + | ||
− | Stdlib.fwrite(Encoding.ASCII.GetBytes( | + | |
Stdlib.fclose(foo); | Stdlib.fclose(foo); | ||
− | + | </source> | |
===Развернем обертки=== | ===Развернем обертки=== | ||
Как указывалось ранее, Mono предоставляет набор упрощенных оберток для базовых структур данных и системных вызовов Unix. Например, | Как указывалось ранее, Mono предоставляет набор упрощенных оберток для базовых структур данных и системных вызовов Unix. Например, | ||
любую информацию о пользователе можно прочесть, создав объект UnixUserInfo таким образом: | любую информацию о пользователе можно прочесть, создав объект UnixUserInfo таким образом: | ||
− | + | <source lang="c"> | |
− | UnixUserInfo user = new UnixUserInfo( | + | UnixUserInfo user = new UnixUserInfo("paul"); |
Console.WriteLine(user.HomeDirectory); | Console.WriteLine(user.HomeDirectory); | ||
− | + | </source> | |
− | Класс UnixUserInfo читает информацию из /etc/passwd, и вы можете увидеть имя пользователя, информацию о группах, их командных оболочках и так далее. Подобные структуры существуют и для файловых систем – следующая строка кода выудит информацию о вашем корневом каталоге: | + | Класс <font color=darkred>UnixUserInfo</font> читает информацию из '''/etc/passwd''', и вы можете увидеть имя пользователя, информацию о группах, их командных оболочках и так далее. Подобные структуры существуют и для файловых систем – следующая строка кода выудит информацию о вашем корневом каталоге: |
− | + | <source lang="c"> | |
− | UnixDriveInfo drive = new UnixDriveInfo( | + | UnixDriveInfo drive = new UnixDriveInfo("/"); |
− | + | </source> | |
− | Затем вы можете узнать объем свободного пространства на диске, прочитав drive.AvailableFreeSpace. Это число возвращается в байтах, поэтому вы можете пожелать удобства ради преобразовать его в гигабайты: | + | Затем вы можете узнать объем свободного пространства на диске, прочитав <font color=darkred>drive.AvailableFreeSpace</font>. Это число возвращается в байтах, поэтому вы можете пожелать удобства ради преобразовать его в гигабайты: |
− | + | <source lang="c"> | |
Console.WriteLine(drive.AvailableFreeSpace / 1024 / 1024 / 1024.0); | Console.WriteLine(drive.AvailableFreeSpace / 1024 / 1024 / 1024.0); | ||
+ | </source> | ||
+ | Последнее <font color=darkred>1024</font> записано как <font color=darkred>1024.0</font>, потому что это заставит Mono преобразовать конечный результат в число с плавающей точкой, а не в целое – в противном случае результат не будет точным! | ||
− | + | Иногда эти обертки имеют собственные методы, как в случае с <font color=darkred>UnixFileInfo</font> – она читает информацию о конкретных файлах, предоставляя вам такие методы, как <font color=darkred>CanAccess()</font>, но, что более важно, позволяет создавать символьные ссылки на файл путем вызова функции <font color=darkred>CreateSymbolicLink()</font>, примерно так: | |
− | + | <source lang="c"> | |
− | Иногда эти обертки имеют собственные методы, как в случае с UnixFileInfo – она читает информацию о конкретных файлах, предоставляя вам такие методы, как CanAccess(), но, что более важно, позволяет создавать символьные ссылки на файл путем вызова функции CreateSymbolicLink(), примерно так: | + | UnixFileInfo file = new UnixFileInfo("file.txt"); |
− | + | file.CreateSymbolicLink("filesym.txt" | |
− | UnixFileInfo file = new UnixFileInfo( | + | </source> |
− | file.CreateSymbolicLink( | + | создаст ссылку '''filesym.txt''' на '''file.txt''', как если бы вы выполнили ''ln -s file.txt filesym.txt'' в командной строке. |
− | + | ||
− | создаст ссылку filesym.txt на file.txt, как если бы вы выполнили ln -s file.txt filesym.txt в командной строке. | + | |
===Звенит сигнал тревоги=== | ===Звенит сигнал тревоги=== | ||
− | Последний метод, который я хочу показать – signal(), он просто показывает, насколько хорошо интегрированы Mono и библиотека C: вы можете попросить Linux вызвать метод C# при поступлении любого сигнала. «Сигнал» в стране C – это то, что происходит, когда ОС пытается по каким-то причинам прервать программу. Например, нажатие Ctrl+C посылает программе SIGINT, что обычно приводит к выходу. А если вы не хотите, чтобы программа завершалась? Что ж, тогда потрудитесь сообщить C#, как поступать при получении SIGINT, и это делается при помощи метода signal(). Он принимает два параметра: сигнал, который вы хотите перехватить, и имя функции, вызываемой при получении сигнала. | + | Последний метод, который я хочу показать – <font color=darkred>signal()</font>, он просто показывает, насколько хорошо интегрированы Mono и библиотека C: вы можете попросить Linux вызвать метод C# при поступлении любого сигнала. «Сигнал» в стране C – это то, что происходит, когда ОС пытается по каким-то причинам прервать программу. Например, нажатие Ctrl+C посылает программе <font color=darkred>SIGINT</font>, что обычно приводит к выходу. А если вы не хотите, чтобы программа завершалась? Что ж, тогда потрудитесь сообщить C#, как поступать при получении <font color=darkred>SIGINT</font>, и это делается при помощи метода <font color=darkred>signal()</font>. Он принимает два параметра: сигнал, который вы хотите перехватить, и имя функции, вызываемой при получении сигнала. |
− | + | ||
− | + | ||
+ | Говоря о <font color=darkred>SIGINT</font> – вот код, который необходимо ввести в программе, чтобы она не отвечала на <font color=darkblue>Ctrl+C</font>: | ||
+ | <source lang="c"> | ||
Stdlib.signal(Mono.Unix.Native.Signum.SIGINT, HandleSigInt); | Stdlib.signal(Mono.Unix.Native.Signum.SIGINT, HandleSigInt); | ||
− | + | </source> | |
− | HandleSigInt – новый метод, который необходимо создать за пределами Main(). Вот пример: | + | <font color=darkred>HandleSigInt</font> – новый метод, который необходимо создать за пределами <font color=darkred>Main()</font>. Вот пример: |
− | + | <source lang="c"> | |
public static void HandleSigInt(int sig) { | public static void HandleSigInt(int sig) { | ||
− | Console.WriteLine( | + | Console.WriteLine("А я против!\n"); |
} | } | ||
− | + | </source> | |
− | Теперь при нажатии Ctrl+C пользователь получит сообщение-отказ; но это не остановит сигнал SIGKILL (посылаемый, когда кто-то выполняет kill -9 <ваш pid>). | + | Теперь при нажатии <font color=darkblue>Ctrl+C</font> пользователь получит сообщение-отказ; но это не остановит сигнал <font color=darkred>SIGKILL</font> (посылаемый, когда кто-то выполняет <font color=darkred>kill -9 <ваш pid></font>). |
Конечно, вы не сможете протестировать обработку вашей программой сигналов прерывания, пока не заставите ее работать бесконечно: | Конечно, вы не сможете протестировать обработку вашей программой сигналов прерывания, пока не заставите ее работать бесконечно: | ||
− | + | <source lang="c"> | |
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite); | System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite); | ||
− | + | </source> | |
На этом наш блиц-тур по интеграции Mono и Unix закончен. Пожалуйста, не забывайте о потенциальных проблемах: утечки памяти – особенно в длительно работающих программах – могут вызвать серьезные осложнения, а привычка работы с Mono способствует небрежному обращению с памятью. Применение родных функций Unix делает миграцию с C на C# быстрой и простой, но в долгосрочной перспективе лучше начать вытеснять функции C-эквивалентами, родными для .NET... | На этом наш блиц-тур по интеграции Mono и Unix закончен. Пожалуйста, не забывайте о потенциальных проблемах: утечки памяти – особенно в длительно работающих программах – могут вызвать серьезные осложнения, а привычка работы с Mono способствует небрежному обращению с памятью. Применение родных функций Unix делает миграцию с C на C# быстрой и простой, но в долгосрочной перспективе лучше начать вытеснять функции C-эквивалентами, родными для .NET... | ||
+ | |||
+ | ==Врезки== | ||
+ | |||
+ | ===Скорая помощь=== | ||
+ | |||
+ | *Не пытайтесь проигнорировать сигнал <font color=darkred>SIGKILL</font> – все равно не удастся: в противном случае некоторые программы никогда не завершались бы! | ||
+ | |||
+ | *Используя <font color=darkred>system()</font> и аргументы, переданные вашей функции, вы можете за минуты сколотить быструю оболочку. Начните с пересылки всего переданного в <font color=darkred>system()</font> и продвигайтесь далее, обрабатывая аргументы и по желанию добавляя собственную функциональность. |
Текущая версия на 18:25, 27 апреля 2008
|
|
|
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
Содержание |
[править] Mono: Назад в Unix
Хотя C# и новый, и передовой, Mono стоит на плечах уродливого монстра Posix. Пол Хадсон пробует заставить Unix-натуру Linux сработаться с .NET...
Имеет ли место садомазохизм в мире компьютеров? Если да, то вот он: я покажу вам, как заставить C# идти бок о бок с Posix и выиграть. Да, Posix – этот дурно задуманный процесс стандартизации, сбивающий с толку программистов, игнорируемый конечными пользователями, и все же подпирающий Linux и другие Unix-подобные ОС. Posix – это набор системных вызовов, интерфейсов и сигналов, определяющий, как мы, разработчики, взаимодействуем с операционной системой. Действующий стандарт Posix весьма обширен, но по сути мы должны заботиться только вот о чем: если вы пишете Posix-совместимый код, он должен работать в любой Posix-совместимой ОС.
Как ни странно, список совместимости включает Windows Vista, точнее, большинство основанных на NT версий Windows, коль скоро они имеют установленными службы Services for Unix. Но с нашей точки зрения важно то, что Linux, FreeBSD, OpenBSD и Syllable практически, а AIX, HP-UX, Minix, OS X и Solaris – полностью поддерживают Posix. Короче, использование функциональности Posix может заставить вас рвать на себе волосы, но, по крайней мере, вы в хорошей компании!
[править] Posix и вы
Имеется два типа людей, в основном использующих Posix: конечные пользователи и разработчики. Значит, практически все! Рассмотрим каждый тип отдельно, начав с пользователя. Да, я помню свои слова, что конечный пользователь игнорирует Posix, но это не совсем верно – фактически, вы используете преимущества инструментов и интерфейсов Posix при каждом обращении к командной строке. Видите ли, Posix заправляет едва ли не всем, что даруют Unix-подобные операционные системы – как работает ваша командная строка, есть ли инструменты типа awk и компиляторов, как происходит взаимодействие программ через каналы. Пусть даже конечные пользователи ничего не знают и знать не хотят о Posix, они обязательно опираются на его набор функций! Что касается разработчиков, то любой из пишущих код на С должен работать с одним из многих интерфейсов ядра и вызовами стандартной библиотеки С, входящими в Posix, и эти функции – например, malloc, system, printf, fopen и другие – доступны везде, куда ни сунься.
Это ставит нас перед вопросом: «Какой прок в использовании Posix?» Общеизвестно, что все системные вызовы Posix скопированы в стандарте среды .NET, с использованием управляемых эквивалентов: вы можете читать и записывать файлы, работать со строками, открывать сокеты, читать данные файловой системы и так далее, не беспокоясь о распределении памяти, потому что .NET освободит все, когда сработает сборщик мусора. Но использование версий Posix дает некоторые преимущества:
- Унаследованный код очень легко портировать. Вы можете взять код на C и запросто перенести его на C#, затем, при добавлении новых функций, добавить расширенную функциональность, присущую C#.
- В том же русле: для C-программистов вполне очевидно, что делает код C# Posix, а это облегчает изучение и сопровождение.
- Вы можете использовать преимущества специфичной для Posix функциональности. Например, чтение данных из файла /etc/passwd в обычном .NET коде необходимо делать вручную, а с использованием инструментов Posix это раз плюнуть.
Итак, использование Posix не лишено преимуществ, но вдобавок имеется одно большое неудобство: львиная доля Posix работает с указателями.
«Указатели?» Так и слышу, как вы охнули. «Привет! Говорят 1980-е! Они требуют обратно свой безумный, анахроничный, осложненный переполнениями буфера доступ к памяти!» Именно так. Указатели – это программные имена, описывающие конкретный участок памяти. Например, переменная – указатель на строку содержит точный адрес в памяти, где располагается строка текста. Понятно, что это прекрасно для быстродействия, так как между программой и оборудованием нет посредников, но ужасно с точки зрения безопасности, потому что программа имеет полную власть над вашим компьютером: даже крошечная щелочка в безопасности может вылиться в захват системы. Теперь, когда вы знаете все о плюсах и минусах Posix, давайте нырнем в него и посмотрим, что тут можно сделать...
[править] Базируемся на Stdlib
Имеется три компонента для поддержки Unix в Mono: Mono.Posix, Mono.Unix и Mono.Unix.Native. Два последних отличаются лишь тем, что Mono.Unix – это небольшая обертка для Mono.Unix.Native, но вы можете использовать ту, где вам комфортнее.
Начнем с простого: создадим новое решение под названием Monix, затем изменим его код Main.cs так:
using Mono.Posix; using Mono.Unix; using Mono.Unix.Native; using System; using System.Text; namespace monix { class Monix { public static void Main(string[] args) { Stdlib.system("ls"); } } }
Этот простой код – основа для всех дальнейших: будем изменять только строку Stdlib.system() да добавлять кое-какие кусочки. Проверьте наличие Mono.Posix и добавьте ссылку на него в проект. В нашем первом методе мы воспользуемся классом Stdlib для вызова system(). Класс Stdlib содержит, в основном, статические методы, то есть вам не нужно создавать объект Stdlib для вызова этих методов. Метод system() (следите за регистром s – он нижний: сейчас мы в стране С!) исполняет любую команду на локальной машине, словно он был введен в командной строке. Для нашего примера это означает запуск ls, поэтому программа выведет список каталогов, как если бы вы сами запустили «ls».
После ввода Stdlib.system(), MonoDevelop должна вывести информацию о параметрах метода system(), и вы увидите, что он принимает строки C#. В этом месте разработчики Mono адаптировали библиотеку вызовов C для лучшей совместимости с программированием .NET – обычно, в терминах С, system() получает const char*, так что использование строк более изящно!
Этот переход существует лишь в некоторых методах. Например, printf() также дружественен к .NET, поэтому вы можете писать код вроде этого:
Stdlib.printf("Hello, %s!\n", "world"); Stdlib.printf(string.Format("Hello, {0}!\n", "world"));
С другой стороны, методы fopen(), fwrite() и fclose() для работы с файлами требуют указателей. В C# указатели известны как IntPtr, потому что это представление указателя в целочисленном типе данных. Эти IntPtr'ы могут восприниматься как данные с неизвестной структурой: их нельзя прочесть без использования специфичных для этих данных методов. Например, файлы открываются так:
IntPtr foo = Stdlib.fopen("file.txt", "w");
Но вы не можете читать или записывать с этого файлового дескриптора без других методов Stdlib. foo IntPtr – всего лишь дескриптор данных, и сам по себе бесполезен. На самом деле, это даже небезопасно: любая память, присвоенная указателю, недоступна сборщику мусора Mono, и необходимо освобождать ее вручную, не то образуется утечка [memory leak]. Вы можете выполнить запись в этот файл, затем закрыть его так:
Stdlib.fwrite(Encoding.ASCII.GetBytes("Hello, world!"), foo); Stdlib.fclose(foo);
[править] Развернем обертки
Как указывалось ранее, Mono предоставляет набор упрощенных оберток для базовых структур данных и системных вызовов Unix. Например, любую информацию о пользователе можно прочесть, создав объект UnixUserInfo таким образом:
UnixUserInfo user = new UnixUserInfo("paul"); Console.WriteLine(user.HomeDirectory);
Класс UnixUserInfo читает информацию из /etc/passwd, и вы можете увидеть имя пользователя, информацию о группах, их командных оболочках и так далее. Подобные структуры существуют и для файловых систем – следующая строка кода выудит информацию о вашем корневом каталоге:
UnixDriveInfo drive = new UnixDriveInfo("/");
Затем вы можете узнать объем свободного пространства на диске, прочитав drive.AvailableFreeSpace. Это число возвращается в байтах, поэтому вы можете пожелать удобства ради преобразовать его в гигабайты:
Console.WriteLine(drive.AvailableFreeSpace / 1024 / 1024 / 1024.0);
Последнее 1024 записано как 1024.0, потому что это заставит Mono преобразовать конечный результат в число с плавающей точкой, а не в целое – в противном случае результат не будет точным!
Иногда эти обертки имеют собственные методы, как в случае с UnixFileInfo – она читает информацию о конкретных файлах, предоставляя вам такие методы, как CanAccess(), но, что более важно, позволяет создавать символьные ссылки на файл путем вызова функции CreateSymbolicLink(), примерно так:
UnixFileInfo file = new UnixFileInfo("file.txt"); file.CreateSymbolicLink("filesym.txt"
создаст ссылку filesym.txt на file.txt, как если бы вы выполнили ln -s file.txt filesym.txt в командной строке.
[править] Звенит сигнал тревоги
Последний метод, который я хочу показать – signal(), он просто показывает, насколько хорошо интегрированы Mono и библиотека C: вы можете попросить Linux вызвать метод C# при поступлении любого сигнала. «Сигнал» в стране C – это то, что происходит, когда ОС пытается по каким-то причинам прервать программу. Например, нажатие Ctrl+C посылает программе SIGINT, что обычно приводит к выходу. А если вы не хотите, чтобы программа завершалась? Что ж, тогда потрудитесь сообщить C#, как поступать при получении SIGINT, и это делается при помощи метода signal(). Он принимает два параметра: сигнал, который вы хотите перехватить, и имя функции, вызываемой при получении сигнала.
Говоря о SIGINT – вот код, который необходимо ввести в программе, чтобы она не отвечала на Ctrl+C:
Stdlib.signal(Mono.Unix.Native.Signum.SIGINT, HandleSigInt);
HandleSigInt – новый метод, который необходимо создать за пределами Main(). Вот пример:
public static void HandleSigInt(int sig) { Console.WriteLine("А я против!\n"); }
Теперь при нажатии Ctrl+C пользователь получит сообщение-отказ; но это не остановит сигнал SIGKILL (посылаемый, когда кто-то выполняет kill -9 <ваш pid>).
Конечно, вы не сможете протестировать обработку вашей программой сигналов прерывания, пока не заставите ее работать бесконечно:
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
На этом наш блиц-тур по интеграции Mono и Unix закончен. Пожалуйста, не забывайте о потенциальных проблемах: утечки памяти – особенно в длительно работающих программах – могут вызвать серьезные осложнения, а привычка работы с Mono способствует небрежному обращению с памятью. Применение родных функций Unix делает миграцию с C на C# быстрой и простой, но в долгосрочной перспективе лучше начать вытеснять функции C-эквивалентами, родными для .NET...
[править] Врезки
[править] Скорая помощь
- Не пытайтесь проигнорировать сигнал SIGKILL – все равно не удастся: в противном случае некоторые программы никогда не завершались бы!
- Используя system() и аргументы, переданные вашей функции, вы можете за минуты сколотить быструю оболочку. Начните с пересылки всего переданного в system() и продвигайтесь далее, обрабатывая аргументы и по желанию добавляя собственную функциональность.