среда, 18 мая 2011 г.

.NET Remoting. Каналы связи.

        Для того, чтобы Remoting-объекты взаимодействовали между собой, они должны обмениваться сообщениями друг с другом. Обмен сообщениями происходит через каналы связи. Каналы связи могут настраиваться как на приём, отправку, так и на приём и отправку одновременно.

        В .NET Remoting существует 3 типа каналов связи:
  • http канал;
  • tcp канал;
  • ipc канал.
        Также, при необходимости, существует возможность написать свой канал.
        Для использования каналов связи в .NET Remoting необходимо подключать пространство имён System.Runtime.Remoting.Channels. Кроме того, должно быть видимо пространство имён System.Runtime.Remoting.
        Для того, чтобы каналы связи работали, нужно обязательно добавить ссылку в проект на System.Runtime.Remoting.
        Рассмотрим более подробно каждый канал.

        HTTP канал


        HTTP канал используется, когда необходима максимальная открытость. По умолчанию в данном канале для передачи сообщений используется протокол SOAP. Он применяет XML-сериализатор для пересылки сообщений между Remoting-объектами.
        Преимущество использования этого канала состоит в том, что через него можно передавать сообщения сквозь брандмауэр через открытые порты. Для использования HTTP канала необходимо подключать пространство имён System.Runtime.Remoting.Channels.Http.

        TCP канал


        TCP канал используется, когда необходима максимальная эффективность передачи данных. По умолчанию в данном канале используется двоичный форматирующий объект для передачи данных между Remoting-объектами. В этом случае сообщения сериализуются в двоичный поток и передаются по сети с помощью обычных сокетов.
        Преимущество использования этого канала состоит в том, что с помощью него достигается максимальная скорость передачи данных между Remoting-объектами. Для использования TCP канала необходимо подключать пространство имён System.Runtime.Remoting.Channels.Tcp.

        IPC канал


        IPC канал используется для связи между процессами в рамках одной машины. Этот канал применяет частные протоколы Windows, проэтому обеспечивает большую производительность, чем HTTP и TCP.
        Для использования IPC канала необходимо подключать пространство имён System.Runtime.Remoting.Channels.Ipc.


        Регистрация канала в приложении


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


using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Channels.Ipc;


class Server
{
        public static void Main(string[] args)
        {
                // Регистрируем HTTP канал
                HttpChannel hchannel = new HttpChannel(1500);
                ChannelServices.RegisterChannel(hchannel);


                // Регистрируем TCP канал
                TcpChannel tchannel = new TcpChannel(1501);
                ChannelServices.RegisterChannel(tchannel);


                // Регистрируем IPC канал
                IpcChannel ichannel = new IpcChannel(1502);
                ChannelServices.RegisterChannel(ichannel);
        }
}


        Как видно в примере, мы регистрируем 3 канала связи, каждый из которых имеет свой уникальный порт. Назначение номеров портов для каналов обязательно для приложения сервера. Для приложения клиента можно не задавать номер порта для канала HTTP, так как к нему никто не обращается.

        HttpChannel hchannel = new HttpChannel();

        В данном случае операционная система назначит ему порт по умолчанию, через который будут передаваться данные.

пятница, 6 мая 2011 г.

.NET Remoting. Типы объектов

        Прежде чем приступить к написанию программ с использованием .NET Remoting, необходимо ознакомиться с базовыми типами, которые данная технология использует. Каждая программа имеет в своём расположении определённый набор данных и памяти, с которыми она может работать. Программа не может использовать чужой участок памяти либо данных. Таким образом появляются границы приложения, за которые оно не может выйти. .NET Remoting позволяет пересекать эти границы.

        В общем случае, все объекты .NET Remoting разделяются на 2 типа: дистанциируемые и недистанциируемые. Отличаются они лишь тем, что дистанциируемые типы способны пересекать границы .NET Remoting, а недистанциируемые - соответственно нет. Если попытаться передать недистанциируемый объект через границу, то будет сгенерировано исключение. Далее подробнее рассмотрим дистанциируемые типы.

        Дистанциируемые типы

        Дистанциируемые типы можно разделить на 3 категории:

    •  передаваемые по значению(marshal-by-value);
    •  передаваемые по ссылке(marshal-by-reference);
    •  контекстно-связанные(context-bound).

        Обозначим сервером -  приложение, объект которого мы хотим получить, а клиентом - приложение, которое хочет получить объект сервера.

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

[Serializable]
class SomeRemoteClass
{
        // Some code
}

        Если мы выполняем передачу по ссылке, то приложение получит не копию объекта, а ссылку на него. Это очень эффективно, если необходимо работать с данными, которые храняться только на сервере, что позволит избежать передачи данных клиенту, кроме передачи ему ещё и объекта. Класс объекта должен быть наследован от класса MarshalByRefObject.
        В общем виде объявление класса объекта будет выглядеть так:

class SomeRemoteClass : MarshalByRefObject
{
        // Some code
}

        Контекстно-связанные типы являются частным случаем типов, передаваемых по ссылке. Экземпляры данного типа должны оставаться в рамках заданного контекста. Внешние по отношению к данному контексту типы не имеют доступ к контекстно-связанному объекту. Класс объекта должен быть наследован от класса ContextBoundObject.
        В общем виде объявление класса объекта будет выглядеть так:

class SomeRemoteClass : ContextBoundObject
{
        // Some code
}

        Далее будем рассматривать примеры с использованием типов, передаваемых по ссылке.

четверг, 5 мая 2011 г.

.NET Remoting. Вступление

        Ничего не стоит на месте, тем более компьютерные технологии. Использование одного компьютера для работы стало недостаточно, необходимо было научиться связывать их между собой. Так появились сети и вместе с ними первые сокеты для связи между машинами. .NET Framework реализовал свои механизмы для связывания двух и более компьютеров, такие как .NET Remoting и WCF.

        WCF - более новая версия межсетевого взаимодействия и является предпочтительней, чем .NET Remoting. Использование этого механизма возможно только вместе с версией .NET Framework 3.0 и  выше. Microsoft рекомендует использовать именно WCF, если есть выбор между этими двумя механизмами.

        Что касается .NET Remoting, то это первый механизм межсетевого взаимодействия, придуманный Microsoft для платформы .NET. Бывают случаи, когда заказчик отказывается переходить на более новую версию .NET Framework и хочет работать только с версиями 2.0 и ниже. В этом варианте нельзя применять WCF и тогда на помощь приходит .NET Remoting.

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

        Далее я буду использовать язык C# для отображения примеров использования .NET Remoting. Также я напишу небольшое приложение для распределённого вычисления, которое будет включать в себя все функциональные возможности данного механизма.

понедельник, 31 января 2011 г.

Qt. Установка собственного курсора в приложение

        В некоторых программах смена курсора в приложении весьма необходима. Возьмём к примеру тот же Paint или Photoshop - довольно непривычно рисовать изображения с помощью одной стрелки. В Qt есть удобный инструмент работы с курсорами, но тоже как и во всех языках не без ньюансов.

        Первый раз я начал загружать курсор в формате Cur. Довольно простой распространённый формат в интернете. Но после долгих поисков, осуществить это я не смог. Оказалось, что Qt не поддерживает формат Cur, они просто отказались от него.

        С одной стороны непонятно, зачем просто выбрасывать его. Но с другой - зачем он нужен, если существует PNG? PNG поддерживает палитру гораздо побогаче, чем Cur, пусть даже занимая немного больше места.

        Подключение курсора к приложению:

        Подключить курсор очень легко. Курсор объявляется с помощью класса QCursor. Я определял курсор как закрытый член класса, поэтому делал его как указатель:

        QCursor* myCursor;

        Дальше берём PNG картинку, которая будет нашим курсором и связываем её в таком виде:

        myCursor = new QCursor(QPixmap("cursor/myCursor.png"), hotX, hotY);

        Картинка загружается как объект QPixmap. Что такое hotX и hotY? Это точка типа int на курсоре, к которой привязывается место клика мышки. Если hotX равно -1, то по координате Х будет взята середина изображения, если hotY равно -1, то по координате Y будет взята середина изображения. Таким образом при значениях -1,-1 местом клика будет центр курсора.

        Чтобы отобразить наш курсор нужно вызвать функцию setCursor. Например, если мы создали виджет с именем wgt, то установка курсора в нём будет выглядеть так:

        wgt.setCursor(*myCursor);

        Если же не создавать указатель на QCursor, как я делал это, то можно выполнить всё одной функцией:

        wgt.setCursor(QCursor(QPixmap("cursor/myCursor.png", hotX, hotY));

        Как видно оба способа довольно просты и понятны. Преимущество PNG курсоров проявляется оссобенно в том, что их легче найти в сети, или же сделать самому.

суббота, 29 января 2011 г.

Qt. QNetworkAccessManager и http(https)

Qt предоставляет очень мощные средства для работы с сетью.  Одним из основных инструментов является класс QNetworkAccessManager. Он позволяет отправлять запросы на сайты и получать ответы с них. Рассмотрим основные элементы для его реализации:

        Используя протокол http:

QNetworkAccessManager* m_manager;
QNetworkReply* m_reply;
QNetworkRequest m_request;
QUrl m_url;
QByteArray m_options;

QNetworkAccessManager – основное звено.  QNetworkRequest запрос к сайту. Он содержит адресс сайта, а также передаваемые для него параметры. QUrl – адрес сайта, m_options – строка с параметрами запроса. QNetworkReply  -  класс для хранения ответа с сервером.
Далее посылаем запрос на сайт и считываем ответ в m_reply:

m_url = "http://www.yoursite.com/script.php";
m_options = "param1=1&param2=2";
m_request.setUrl(m_url);
m_reply = m_manager->post(m_request, m_options);

connect(m_reply, SIGNAL(finished()), this, SLOT(slotFinished()));
connect(m_reply, SIGNAL(readyRead()), this, SLOT(slotRead()));

В данном случае мы выполняем запрос с помощью метода Post, но также можно посылать запрос с методом Get. Отличие лишь будет в том, что адрес сайта и параметры нужно обьеденить в одну строку:

m_reply = m_manager->post("http://www.yoursite.com/script.php? param1=1&param2=2");


        При обращении к серверу сайта, QNetworkReply сгенерирует 2 сигнала – finished() и readyRead(). Первый говорит о том что все операции завершены, и объект класса QNetworkReply уже не будет изменён(после этого сигнала рекомендуется удалять ответ m_reply: m_reply->deleteLater()), а второй говорит о том, что данные считаны ими можно оперировать. Присоединяем эти сигналы к нашим слотам и производим считывание данных.

QByteArray htmlPage = m_reply->readAll();

Функция readAll()  возвращает результат запроса в виде QByteArray. После этого можно записывать данные в файл, либо оперировать ими в программе.

Используя протокол https:

При использовании протокола https программа не сильно изменяется. В адресе сайта просто вместо http пишется https. Но появляются некоторые трудности.
Первая из них, это игнорирование ssl ошибок при соединении.  Её легко решить так: 

connect(m_reply, SIGNAL(sslErrors(QList<QSslError>)), m_reply, SLOT(ignoreSslErrors()));

А вторая, это отсутствие алгоритмов шифрования в Qt для соединения с сервером. Возникают такие ошибки при соединении:

QSslSocket: cannot call unresolved function SSLv3_client_method
QSslSocket: cannot call unresolved function SSL_CTX_new
QSslSocket: cannot call unresolved function SSL_library_init
QSslSocket: cannot call unresolved function ERR_get_error
QSslSocket: cannot call unresolved function ERR_error_string


Если видите эти строки, вам нужен OpenSsl. Его можно достать на официальном сайте. Я писал на ОС Windows, так что последние версии сборок можно достать здесь .

После подключения OpenSsl к Qt, проблемы больше не возникнут. Программа обратиться к сайту и получит ответ от него.