2015-01-23 5 views
0

웹 서비스를 공격하는 방법을 알아 내고, 동시에 파싱하는 동안 json을 파싱하고 deserialize하는 동안 내 머리카락을 찢어 내고 있습니다. 전체 문서 저장 (500mb +). 효과적으로, 내 클래스에 바로 SAX 스타일 구문 분석을 사용하여 libcurl과 rapidjson을 연결하려고합니다.스트리밍 역 직렬화에 대한 Libcurl + rapidjson?

어쩌면 나는이 잘못에 대해 생각하고있다. 그러나 curl_writeback 중에는 json 텍스트 스트림에 수신 된 데이터를 추가하는 것이 현재의 생각이다. 내가 고민하는 것은 rapidjson 구문 분석 엔진을 시작하고 컬링 쓰기 되돌림에서 오는 데이터 블록을 기다리는 방법입니다. 새로운 스트림 버퍼가 수신 될 때까지 미완료 된 토큰이 처리되기 전에 정지. 이전 버퍼를 비우고 싶기 때문에 버퍼를 추가하고 싶지 않습니다.

이전에이 작업을 수행 한 사람이 있습니까? 여기

몇 가지 개념을 설명하는 코드 ...하지만 분명히 완료되지 않은 (모든 잘못 아마와!) 여기에

가가에 콜백을 수행하는 방법을 알 수 있도록 curl_write 정보를 전달하는 구조입니다 파서.

rapidjson::Reader reader; 
CurlHandler handler; 
ParseHandler parser; 
handler.reader = &reader; 
handler.parsehandler = &parser; 
SetOption(CURLOPT_WRITEDATA, (void *) &handler); 

ParseHandler는 SAX 구문 분석을 할 rapidjson가 필요로하는 클래스입니다 다음과 같이

struct CurlHandler { 
    stringstream *data; 
    Reader *reader; 
    void *parsehandler; 
}; 

는 그런 요청을 시작하기 전에, 나는 구조를 채 웁니다. 나는 확실히이보다 쉽게 ​​응답이 희망

static size_t curl_write(void *ptr, size_t size, size_t nmemb, void *CurlHandlerPtr) { 
    CurlHandler *handler = (CurlHandler *) CurlHandlerPtr; 

// handler->reader.Parse(handler->data, handler->parsehandler); ???????? 

    return 1; 
} 

: 아이디어는 curl_write 동안 rapidjson 파서 (어떻게 든)를 호출하는 것이 었습니다.

#pragma once 
#include <string> 
#include <iostream> 
#include "curl\curl.h" 
#include "rapidjson\rapidjson.h" 
#include "rapidjson\reader.h" 

using namespace std; 
using namespace rapidjson; 

struct CurlHandler { 
    stringstream *data; 
    Reader *reader; 
    void *parsehandler; 
}; 

static size_t curl_write(void *ptr, size_t size, size_t nmemb, void *CurlHandlerPtr) { 
    CurlHandler *handler = (CurlHandler *) CurlHandlerPtr; 

// handler->reader.Parse(handler->data, handler->parsehandler); ???????? 

    return 1; 
} 


class ParseHandler { 
    bool Null() { cout << "Null()" << endl; return true; } 
    bool Bool(bool b) { cout << "Bool(" << boolalpha << b << ")" << endl; return true; } 
    bool Int(int i) { cout << "Int(" << i << ")" << endl; return true; } 
    bool Uint(unsigned u) { cout << "Uint(" << u << ")" << endl; return true; } 
    bool Int64(int64_t i) { cout << "Int64(" << i << ")" << endl; return true; } 
    bool Uint64(uint64_t u) { cout << "Uint64(" << u << ")" << endl; return true; } 
    bool Double(double d) { cout << "Double(" << d << ")" << endl; return true; } 
    bool String(const char* str, SizeType length, bool copy) { 
     cout << "String(" << str << ", " << length << ", " << boolalpha << copy << ")" << endl; 
     return true; 
    } 
    bool StartObject() { cout << "StartObject()" << endl; return true; } 
    bool Key(const char* str, SizeType length, bool copy) { 
     cout << "Key(" << str << ", " << length << ", " << boolalpha << copy << ")" << endl; 
     return true; 
    } 
    bool EndObject(SizeType memberCount) { cout << "EndObject(" << memberCount << ")" << endl; return true; } 
    bool StartArray() { cout << "StartArray()" << endl; return true; } 
    bool EndArray(SizeType elementCount) { cout << "EndArray(" << elementCount << ")" << endl; return true; } 
}; 

class StreamTest { 
private: 
    string _username; 
    string _password; 

    CURL *_curl; 
    CURLcode _error; 

public: 
    StreamTest() { 
     curl_global_init(CURL_GLOBAL_ALL); 
     _curl = curl_easy_init(); 
    }; 
    ~StreamTest() { 
     curl_global_cleanup(); 
    }; 

    int Initialize(string username, string password) { 
     _username = username; 
     _password = password; 
     return 0; 
    } 

    int Get(std::string url) { 
     CURLcode result; 

     rapidjson::Reader reader; 
     CurlHandler handler; 
     ParseHandler parser; 
     handler.reader = &reader; 
     handler.parsehandler = &parser; 

     std::string s = _username; s += ":"; s += _password; 

     SetOption(CURLOPT_USERPWD, s.c_str()); 
     SetOption(CURLOPT_URL, url.c_str()); 
     SetOption(CURLOPT_WRITEFUNCTION, curl_write); 
     SetOption(CURLOPT_WRITEDATA, (void *) &handler); 
     result = curl_easy_perform(_curl); 

     return 0; 
    } 

    template <typename ValueType> 
    StreamTest& SetOption(CURLoption opt, ValueType val) { 
     if(_curl && _error == CURLE_OK) { 
      _error = curl_easy_setopt(_curl, opt, val); 
     } 
     return *this; 
    } 
}; 

int _tmain(int argc, _TCHAR* argv[]) { 
    StreamTest http; 

    http.Initialize("guest", "passwd"); 

    http.Get("http://localhost/GetData"); 

    cin.get(); 
} 

EDIT :

이상적 _tmain http.Get의 함수로 탈 직렬화 될 개체에 대한 참조를 전달 것이다

여기 문맥 전체 코드이다. 객체는 일종의 콜백으로 rapidjson에서 모든 SAX 이벤트를 수신합니다.

답변

0

RapidJSON의 디자인은 구문 분석하는 동안 일시 중지/다시 시작을 지원하지 않습니다. 이렇게하면 파싱 상태를 백업/복원하는 데 많은 오버 헤드가 추가됩니다.

그러나 언급 된 요구 사항은 실제로 멀티 스레드를 사용하는 Libcurl의 Multi interface을 사용하여 해결할 수 있습니다.

libcurl의 fopen.c 예제는 HTTP GET을 표준 FILE I/O API로 에뮬레이트하는 방법을 보여줍니다. 이 예제를 사용하면 HTTP에서 JSON 구문 분석을 지원하도록 rapidjson::FileReadStream을 수정하면 편리합니다.

일반적으로 개발자는 RapidJSON을 사용할 때 이러한 문제를 해결하기 위해 멀티 스레드를 사용할 수 있습니다.

+0

마일로, 감사합니다. 그러나 구문 분석 속도는 문제가 아니므로 멀티 스레딩이 필요하지는 않습니다. RapidJson은 빨리 망할 것입니다. 문제는 주로 메모리 소비입니다. 만약 내가하고있는 모든것이 객체로 forward 읽기 전용 파싱이라면 나는 500MB + 파일을 메모리에로드하지 않을 것이다. – user3072517

+0

내 대답에 접근 방식을 사용하면 메모리를 줄일 수 있다고 생각합니다.SAX 인터페이스와 HTTP에서 JSON 스트리밍을 사용하는 한 전체 JSON을 메모리에 저장할 필요는 없습니다. –