Thrift client-server

[ ROT ]

13 Sep 2013

Client написан на C++, server - на Python. Thrift позволяет вызывать одному субъекты вызывать методы другого.

thrift

Описывает две функции: ping и подсчёт количества тэгов.

#!/usr/local/bin/thrift

namespace cpp Parser
namespace py Parser

service Parser {
  void ping(),
  i32 count(1:string page, 2:string tag)
}

server

Python для парсинга страниц на количество тэгов. Принимает на вход текст страницы и искомый тэг. На выходе возвращает количество таких тэгов на странице.

#!/usr/bin/python
# -*- coding: utf-8 -*-
__author__ = 'Messiah'

import sys

sys.path.append('./gen-py')

from Parser import Parser
from Parser.ttypes import *
from re import findall, MULTILINE, DOTALL, IGNORECASE
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from thrift.server import TServer

class ParserHandler:
    def __init__(self):
        self.log = {}

    def ping(self):
        print "ping()"

    def count(self, page, tag):
        c = len(findall("<{0}.*?>.*?</{0}>".format(tag),
                        page, MULTILINE | DOTALL | IGNORECASE))
        c += len(findall("<{0}[^<>]*?/>".format(tag),
                         page, MULTILINE | DOTALL | IGNORECASE))
        return c

handler = ParserHandler()
processor = Parser.Processor(handler)
transport = TSocket.TServerSocket(port=9090)
tfactory = TTransport.TBufferedTransportFactory()
pfactory = TBinaryProtocol.TBinaryProtocolFactory()

server = TServer.TSimpleServer(processor, transport, tfactory, pfactory)

print "Starting python server..."
try:
    server.serve()
except KeyboardInterrupt:
    print "Kill signal received..."
print "done!"

client

С++. Принимает на вход URL и тэг. Скачивает страницу, отправляет текст серверу, возвращает количество искомых тегов.

#include "./gen-cpp/Parser.h"
#include <iostream>
#include <curl/curl.h>
#include <thrift/transport/TSocket.h>
#include <thrift/transport/TBufferTransports.h>
#include <thrift/protocol/TBinaryProtocol.h>

using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
using namespace std;
using namespace Parser;

int somecallback(char * data, int size, int nmemb, std::string* buffer){
       buffer->append(std::string(data));
       return (size* nmemb);
    }

int main(int argc, char **argv) {
    if (argc < 3) {
        cout << "Using: " << argv[0] << " <URL> <tag>" << endl;
        return 1;
    }
    string buffer;
    CURL * curl = curl_easy_init();
    curl_easy_setopt(curl, CURLOPT_URL, argv[1]);
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, somecallback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
    curl_easy_perform(curl);

    string tag = argv[2];

    boost::shared_ptr<TSocket> socket(new TSocket("localhost", 9090));
    boost::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
    boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));

    ParserClient client(protocol);
    transport->open();
    //client.ping();
    int c = client.count(buffer, tag);
    cout << tag << " = " << c << endl;
    transport->close();
    return 0;
}

Компиляция и зависимости

Требует установленного thrift, libcurl, g++

Для С++ thrift успешно собирается по инструкции с сайта. Python у меня его не увидел (возможно недособрал) - решается установкой python-thrift:

pip install thrift

Сборка происходит с помощью утилиты make.

Makefile

.PHONY: build thrift client clean

build: thrift client

thrift: parser.thrift
	thrift --gen cpp parser.thrift
	thrift --gen py  parser.thrift

client: thrift client.cpp
	CFLAGS="-O3" g++ -DHAVE_INTTYPES_H -DHAVE_NETINET_IN_H -Wall -lthrift -lcurl gen-cpp/Parser.cpp -o client client.cpp

clean:
	rm -rf ./gen-*/ client

На выходе будет доступно два исполняемых файла: server.py и client.elf

GitHub