Хочу поделиться с вами примером того как можно использовать такую удобную штуку как Thrift в своих .NET проектах.
Для тех кто не знает, Thrift — это фреймворк для облегчения взаимодействия между кодом написанным на разных языках, а именно C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk и OCaml.
Thrift используется и был изначально создан Facebook. Так же неоднократно упоминался здесь, на Хабре, но примеров для .NET я не нашел, кстати пошаговое руководство для .NET отсутствует и на официальном сайте. В гугле если честно, тоже не смог найти, хотя может плохо искал.
Thrift позволяет один раз описать сервис, структуры данных и даже исключения, а потом сгенерировать код для всех поддерживаемых языков. Таким образом, если вы, например, напишете сервер с использованием Thrift на .NET, то вы
Итак нам понадобится:
Оба можно взять отсюда
Так же в конце статьи я дам исходники рабочего приложения, в них есть уже собранная библиотека и компилятор, можно взять все оттуда.
Шаг 1: Подготовка
Итак после того как вы скачали исходники, распаковывайте их в любую директорию и заходите в
Открывайте солюшен и собирайте проект. После чего у вас есть библиотека Thrift.dll.
Шаг 2: Создаем наши проекты
Создайте 3 проекта в Visual Studio и объедините их в солюшен.
Берете полученную ранее библиотеку Thrift.dll и скачанный Thrift компилятор и кладете их в директорию в солюшене.
Шаг 3: Генерируем код из .thrift файла
Опишем наш сервис и структуру данных. Для этого создадим файл TimeService.thrift с таким содержанием:
и положим его в проект TimeServerCore . Так же добавьте в проект ссылку(reference) на Thrift.dll полученную в Шаге №1.
Важно: Не сохраняйте .thrift файл в Unicode кодировке, у меня Thrift компилятор не захотел ничего из него генерировать, до тех пор пока я в студии в File->Advanced Save Options не сменил Unicode на другую кодировку.
В этом файле и содержится практически все описание нашего клиент-серверного приложения.
Можно вручную вызвать Thrift компилятор указав ему .thrift файл и получить необходимые классы, но лучше добавить pre-build event в наш проект, на случай если мы будем менять TimeService.thrift
С моей иерархией директорий, получился вот такой вызов
«thrift-0.5.0.exe» — собственно сам компилятор, опция "-gen csharp" говорит ему что нам нужны классы для C#, опция "-o $(ProjectDir)" говорит куда положить результат, ну и остаток "$(ProjectDir)\TimeService.thrift" указывает какой собственно файл компилировать.
Таким образом после билда(на самом деле до, у нас же pre-build event) TimeServerCore у нас создадутся 2 класса
TimeInfoStruct.cs — структура для передачи времени, в принципе метод сервиса мог просто вернуть строку, но со структурой интерестнее.
TimeService.cs — сервис, с нашим единственным методом.
Так же в них есть код отвечающий за сериализацию/десериализайию, наглядный ToString, и кое-что еще.
Лежать они будут в \TimeServerCore\gen-csharp\TimeServer\Thrift. Директория gen-csharp будет всегда, видимо для того что бы раскидать по разным папкам код для разных языков, если указано больше одного языка, а две директории ниже по иерархии (\TimeServer\Thrift) создаются из за namespace, указанного в .thrift файле.
Необходимо добавить эти 2 файла в проект, у меня после этого получилось так:
Шаг 4: Сервер
Займемся сервером. Добавьте в TimeServer ссылку(reference) на Thrift.dll, а так же на проект TimeServerCore в нашем солюшене. После чего создайте новый класс TimeServiceImplementation.cs.
В этом классе мы реализуем методы нашего сервиса. В сгенерированном файлике TimeService.cs Thrift для нас создал специальный интерфейс, который мы должны реализовать.
Вот интерфейс:
как видим там есть всего 1 функция, которую мы описали в .thrift файле.
Вот моя реализация этого интерфейса:
И так все почти готово, необходимо заставить сервер запускаться при старте приложения и ждать клиентов:
Мы создаем нашу реализацию интерфейса сервера, после чего запускаем сервер на 1337 порту и ждем соединений.Вот и весь код необходимый для создания простейшего сервера.
Помимо реализации сервера TSimpleServer в библиотеке Thrift.dll есть TThreadedServer и TThreadPoolServer.
Шаг 5: Клиент
Реализация клиента еще проще:
Не забудьте добавить в проект клиента ссылку(reference) на Thrift.dll и проект TimeServerCore.
После чего, можно запустить сначала сервер, а затем клиент. Который должен вывести текущее время.
Вот и все. Причем большую часть времени мы потратили на первоначальную настройку и знакомство с Thrift, да и то не так много. Теперь можно добавлять в наш .thirft файл новые структуры и методы в сервис, после чего лишь писать реализации серверных методов.
Ну а если понадобятся клиенты или серверы написанные на других языках, то классы для них так же можно сгенерировать c помошью Thrift.
Например, с использованием Thrift был получен .NET клиент для БД Cassandra. Хотя создавая Cassandra вряд ли Facebook планировали поддерживать .NET клиентов :)
Вот обещанные исходники:
dl.dropbox.com/u/3945288/Thirft-Time-Server-.NET-Sample.zip
github.com/kmuzykov/Thirft-Time-Server-.NET-Sample
Вот ссылка на Thrift Wiki, хотя там не много информации для .NET.
Для тех кто не знает, Thrift — это фреймворк для облегчения взаимодействия между кодом написанным на разных языках, а именно C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk и OCaml.
Thrift используется и был изначально создан Facebook. Так же неоднократно упоминался здесь, на Хабре, но примеров для .NET я не нашел, кстати пошаговое руководство для .NET отсутствует и на официальном сайте. В гугле если честно, тоже не смог найти, хотя может плохо искал.
Thrift позволяет один раз описать сервис, структуры данных и даже исключения, а потом сгенерировать код для всех поддерживаемых языков. Таким образом, если вы, например, напишете сервер с использованием Thrift на .NET, то вы
- Сэкономите кучу времени для написания клиент серверного приложения, например с использованием сокетов.
- Почти автоматически получаете клиентов на всех поддерживаемых языках.
Итак нам понадобится:
- Исходники Thrift — они нужны нам для того что бы собрать библиотеку (class library) для подключения в наш проект.
- Thrift компилятор — консольная утилита которая генерирует код на необходимом нам языке из .thrift файлов
Оба можно взять отсюда
Так же в конце статьи я дам исходники рабочего приложения, в них есть уже собранная библиотека и компилятор, можно взять все оттуда.
Шаг 1: Подготовка
Итак после того как вы скачали исходники, распаковывайте их в любую директорию и заходите в
thrift-0.5.0\lib\csharp\src\
Открывайте солюшен и собирайте проект. После чего у вас есть библиотека Thrift.dll.
Шаг 2: Создаем наши проекты
Создайте 3 проекта в Visual Studio и объедините их в солюшен.
- TimeServer — консольное приложение. Сервер. Будет ждать соединения
- TimeServerClient — консольное приложение. Клиент. Будет соединятся с сервером и спрашивать время.
- TimeServerCore — библиотека (class library). В ней будут лежать сгенерированные C# классы и исходный файл .thrift(о нем далее)
Берете полученную ранее библиотеку Thrift.dll и скачанный Thrift компилятор и кладете их в директорию в солюшене.
Шаг 3: Генерируем код из .thrift файла
Опишем наш сервис и структуру данных. Для этого создадим файл TimeService.thrift с таким содержанием:
namespace csharp TimeServer.Thrift
//Structure for returning Time
struct TimeInfoStruct{
1: string Time
}
//Service
service TimeService
{
TimeInfoStruct GetTime()
}
* This source code was highlighted with Source Code Highlighter.
и положим его в проект TimeServerCore . Так же добавьте в проект ссылку(reference) на Thrift.dll полученную в Шаге №1.
Важно: Не сохраняйте .thrift файл в Unicode кодировке, у меня Thrift компилятор не захотел ничего из него генерировать, до тех пор пока я в студии в File->Advanced Save Options не сменил Unicode на другую кодировку.
В этом файле и содержится практически все описание нашего клиент-серверного приложения.
Можно вручную вызвать Thrift компилятор указав ему .thrift файл и получить необходимые классы, но лучше добавить pre-build event в наш проект, на случай если мы будем менять TimeService.thrift
С моей иерархией директорий, получился вот такой вызов
$(SolutionDir)\Thrift\thrift-0.5.0.exe -gen csharp -o $(ProjectDir) $(ProjectDir)\TimeService.thrift
«thrift-0.5.0.exe» — собственно сам компилятор, опция "-gen csharp" говорит ему что нам нужны классы для C#, опция "-o $(ProjectDir)" говорит куда положить результат, ну и остаток "$(ProjectDir)\TimeService.thrift" указывает какой собственно файл компилировать.
Таким образом после билда(на самом деле до, у нас же pre-build event) TimeServerCore у нас создадутся 2 класса
TimeInfoStruct.cs — структура для передачи времени, в принципе метод сервиса мог просто вернуть строку, но со структурой интерестнее.
TimeService.cs — сервис, с нашим единственным методом.
Так же в них есть код отвечающий за сериализацию/десериализайию, наглядный ToString, и кое-что еще.
Лежать они будут в \TimeServerCore\gen-csharp\TimeServer\Thrift. Директория gen-csharp будет всегда, видимо для того что бы раскидать по разным папкам код для разных языков, если указано больше одного языка, а две директории ниже по иерархии (\TimeServer\Thrift) создаются из за namespace, указанного в .thrift файле.
Необходимо добавить эти 2 файла в проект, у меня после этого получилось так:
Шаг 4: Сервер
Займемся сервером. Добавьте в TimeServer ссылку(reference) на Thrift.dll, а так же на проект TimeServerCore в нашем солюшене. После чего создайте новый класс TimeServiceImplementation.cs.
В этом классе мы реализуем методы нашего сервиса. В сгенерированном файлике TimeService.cs Thrift для нас создал специальный интерфейс, который мы должны реализовать.
Вот интерфейс:
public class TimeService { //лежит внутри класса
public interface Iface {
TimeInfoStruct GetTime();
}
//...
}
* This source code was highlighted with Source Code Highlighter.
как видим там есть всего 1 функция, которую мы описали в .thrift файле.
Вот моя реализация этого интерфейса:
class TimeServiceImplementation : TimeService.Iface
{
public TimeInfoStruct GetTime()
{
return new TimeInfoStruct() { Time = DateTime.Now.ToString() };
}
}
* This source code was highlighted with Source Code Highlighter.
И так все почти готово, необходимо заставить сервер запускаться при старте приложения и ждать клиентов:
static void Main(string[] args)
{
TimeServiceImplementation service = new TimeServiceImplementation();
TProcessor processor = new TimeService.Processor(service);
TServerTransport transport = new TServerSocket(1337, 1000);
TServer server = new TSimpleServer(processor, transport);
server.Serve();
}
* This source code was highlighted with Source Code Highlighter.
Мы создаем нашу реализацию интерфейса сервера, после чего запускаем сервер на 1337 порту и ждем соединений.Вот и весь код необходимый для создания простейшего сервера.
Помимо реализации сервера TSimpleServer в библиотеке Thrift.dll есть TThreadedServer и TThreadPoolServer.
Шаг 5: Клиент
Реализация клиента еще проще:
static void Main(string[] args)
{
TTransport transport = new TSocket("localhost", 1337);
TProtocol proto = new TBinaryProtocol(transport);
TimeService.Client client = new TimeService.Client(proto);
transport.Open();
TimeInfoStruct result = client.GetTime();
Console.WriteLine(result.ToString());
Console.ReadKey();
}
* This source code was highlighted with Source Code Highlighter.
Не забудьте добавить в проект клиента ссылку(reference) на Thrift.dll и проект TimeServerCore.
После чего, можно запустить сначала сервер, а затем клиент. Который должен вывести текущее время.
Вот и все. Причем большую часть времени мы потратили на первоначальную настройку и знакомство с Thrift, да и то не так много. Теперь можно добавлять в наш .thirft файл новые структуры и методы в сервис, после чего лишь писать реализации серверных методов.
Ну а если понадобятся клиенты или серверы написанные на других языках, то классы для них так же можно сгенерировать c помошью Thrift.
Например, с использованием Thrift был получен .NET клиент для БД Cassandra. Хотя создавая Cassandra вряд ли Facebook планировали поддерживать .NET клиентов :)
Вот обещанные исходники:
dl.dropbox.com/u/3945288/Thirft-Time-Server-.NET-Sample.zip
github.com/kmuzykov/Thirft-Time-Server-.NET-Sample
Вот ссылка на Thrift Wiki, хотя там не много информации для .NET.