欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于http的protobuf服务实现

程序员文章站 2022-05-27 23:43:41
...

 

通常webapi实现通过http get/post请求,返回文本型的json,xml等字符串。本文以Tomcat8为web服务器,借助protobuf框架,响应二进制数据。

由于protobuf协议能跨语言,我们可以用java servlet实现服务端,C/C++实现客户端,达到各模块解耦目的。双方需设置ContentType为application/x-protobuf。

 

1. 准备proto文件

 

package qwd.kettas;

// 请求结构
message CTestReq
{
        optional uint32 ShopId = 1;   // 店铺ID
}

message CProduct
{
        optional uint32 Id = 1;      // 商品ID
        optional bytes Name = 2;     // 商品名称
        optional double price = 3;   // 商品价格
}

// 响应结构
message CTestResp
{
        optional int32 Total = 1;        // 商品总数
        repeated CProduct Product = 2;   // 商品数组
}

 

2. Java Servlet服务

 

/**
 * Servlet 服务实现,接收post请求,响应protocol buffer二进制数据
 */
protected void service( HttpServletRequest req, HttpServletResponse resp )
	throws ServletException, IOException {
	/*	
	 * 注:用in.read() 无数据部分填充0,会导致parseFrom()失败,不可行。
	byte[] postBuf = new byte[128];
	InputStream in = req.getInputStream();
	int len = in.read( postBuf );
	 */
	
	// protobuf 解析参数
	CTestReq tReq = CTestReq.parseFrom( req.getInputStream() );	// InputStream作为参数
	int shopid = tReq.getShopId();
	
	// 准备数据
	CTestResp.Builder pBuilder = CTestResp.newBuilder();
	pBuilder.setTotal(2);
	
	// 产品一
	CProduct.Builder pProBuild1 = CProduct.newBuilder();
	pProBuild1.setId( shopid + 1001 );
	pProBuild1.setName( ByteString.copyFrom("小明","UTF-8") );	// 字符串需要通过ByteString转化,最好定义string
	pProBuild1.setPrice(15.8);
	pBuilder.addProduct( pProBuild1 );
	
	// 产品二
	pProBuild1 = CProduct.newBuilder();
	pProBuild1.setId( shopid + 1002 );
	pProBuild1.setName( ByteString.copyFrom("小王","UTF-8") );
	pProBuild1.setPrice(29.8);
	pBuilder.addProduct( pProBuild1 );
	
	// reponse
	CTestResp pResp = pBuilder.build();
	System.out.println( "Data: " + pResp.toString() );
	
	// 序列化
	byte[] buff = pResp.toByteArray();
	
	// 响应,设置HTTP头部为: application/x-protobuf
	resp.setContentType("application/x-protobuf");
	resp.getOutputStream().write( buff );	// 发送
}

 

 

3. 客户端测试

 

// 数据回调函数
size_t OnWriteData( void* buffer, size_t size, size_t nmemb, void *lpVoid )
{
        std::string* str = dynamic_cast<std::string*>((std::string *)lpVoid);
        if ( NULL == str || NULL == buffer )
        {   
                return -1; 
        }   

        char* pData = (char*)buffer;
        str->append(pData, size * nmemb);
        return nmemb;
}


// curl模拟post请求
void TestCurl()
{
        printf( "\n****************TestCurl*******************\n" );
        const char *url = "http://10.14.230.7:8080/protoweb/proto";
        CTestReq req;
        CTestResp resp;
        string sReq;
        string sResp;

        req.set_shopid( 1500 );

        // 序列化请求
        if ( !req.SerializeToString(&sReq) )
                return;

        curl_slist *m_header = NULL;
        m_header = curl_slist_append( m_header, "Content-Type: application/x-protobuf" );  // 设置消息头

        CURL *curl = curl_easy_init();
        curl_easy_setopt( curl, CURLOPT_HTTPHEADER, m_header ); // Header
        curl_easy_setopt( curl, CURLOPT_REFERER, "nginx" );
        curl_easy_setopt( curl, CURLOPT_VERBOSE, 1L );
        curl_easy_setopt( curl, CURLOPT_URL, url );
        curl_easy_setopt( curl, CURLOPT_NOSIGNAL, 1);
                                          
        curl_easy_setopt( curl, CURLOPT_POSTFIELDS, sReq.c_str() );             // Post
        curl_easy_setopt( curl, CURLOPT_POSTFIELDSIZE, sReq.length() );
        curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, OnWriteData );
        curl_easy_setopt( curl, CURLOPT_WRITEDATA, (void*)&sResp );     // Accept data

        CURLcode ret = curl_easy_perform( curl );
        assert( ret == CURLE_OK );
        curl_easy_cleanup( curl );
        curl_slist_free_all( m_header );

        // 反序列化数据
        if ( !resp.ParseFromString(sResp) )
                return;

        printf( "Response: %s\n", resp.DebugString().c_str() );
}

 

执行结果,curl发起post请求,返回46字节内容:

 

基于http的protobuf服务实现
            
    
    博客分类: C/C++java webapiprotobufx-protobuftomcat 

 

 

  • 基于http的protobuf服务实现
            
    
    博客分类: C/C++java webapiprotobufx-protobuftomcat
  • 大小: 33.7 KB