Protocol Buffer在C++網絡編程中使用教程

1. 下載 Protocol Buffers v2.6.1

https://github.com/google/protobuf/releases/tag/v2.6.1

2.使用 vs2012 編譯 protobuf-2.6.1\vsprojects\protobuf.sln

在解決方案中 逐項進行編譯,在Debug目錄中生成lib和exe,
文件生成清單如下:
libprotobuf.lib
libprotobuf-lite.lib
libprotoc.lib 

lite-test.exe
protoc.exe
test_plugin.exe
tests.exe

3. protobuf測試:

創建兩個工程(),每個工程都要添加 protobuf頭文件 和 lib文件。

(1). 在屬性-> C/C++ ->常規 (附加包含目錄)
     添加 C:\xiaofan\tools\protobuf\protobuf-2.6.1\src

(2). 在屬性-> 鏈接器 ->常規 (附加庫目錄)
     添加 C:\xiaofan\tools\protobuf\protobuf-2.6.1\libs 
     (注意: 此處的 libs 是我自己創建的,把Debug中的 lib 拷貝了進去 )

4.創建people.proto:

package PeopleT.Test;     
message People  
{     
  required string name = 1;     
  required int32 id = 2;     
  required string email = 3;     
};

編譯生成頭文件:
找到protoc.exe,運行cmd :
protoc -I=. --cpp_out=. people.proto
生成 people.pb.h 和 people.pb.cc

5.程序調用

使用VS2012分別創建protobuf_client和protobuf_server 程序。
把people.pb.h 和 people.pb.cc加入程序,在主程序中使用命名空間,

#include "people.pb.h"
using namespace PeopleT::Test;

注意:

(1).在windows下寫socket程序時,需要加入 #pragma comment( lib, "ws2_32.lib")  ,該庫主要提供網絡相關API的支持。

(2).編譯過程中如果遇到問題,請參見之前的文章:

在VS2012中 集成protobuf 文件時, 編譯出現問題

詳情參見程序如下:

// 客戶端程序

#include "stdafx.h"
#include <stdio.h>
#include <WinSock2.h>  
#include <iostream>
#include <string>
#include <ctime>
#include "people.pb.h"
using namespace std;
using namespace PeopleT::Test;

#pragma comment( lib, "ws2_32.lib")

const int BUFFSIZE = 128;

int _tmain(int argc, _TCHAR* argv[])
{
	WSADATA     wsd;               //WSADATA變量  
	SOCKET socketfd;               //服務器套接字  
	struct sockaddr_in seraddr ;   //服務器地址  
	string hostip = "127.0.0.1"; 


	//初始化套結字動態庫  
	if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)  
	{
		cout << "WSAStartup failed!" << endl;  
		return -1;  
	}

	IPPROTO_TCP;
	//鏈接,嘗試3次
	for(int i = 0 ; i < 3;++i)
	{
		if((socketfd = socket(AF_INET,SOCK_STREAM,0)) > 0)
		{
			cout<<"create socket success..."<<endl;
			break;
		}
		Sleep(2000);
	}

	if(INVALID_SOCKET == socketfd)
	{
		cout<<"socket failed"<<endl;
		WSACleanup();//釋放套接字資源  
		return -1;
	}

	
	//地址置空
	memset( &seraddr, sizeof(seraddr) ,0);
	//設置服務器地址  
	seraddr.sin_family = AF_INET ;
	seraddr.sin_port = htons(9999);
	seraddr.sin_addr.s_addr = inet_addr(hostip.c_str());
	//嘗試連接到服務端地址
	if(connect(socketfd,(struct sockaddr *)&seraddr, sizeof(seraddr)) < 0)
	{
		cout<<"connect to server failed ..."<<endl;
		closesocket(socketfd);
		WSACleanup();       //釋放套接字資源  
		return -1;
	}

	People myprotobuf;
	char buff[BUFFSIZE];

	while( true )
	{
		int curtime = time(NULL) ;
		//以下方法的實現可以Test.pb.h中找到
		myprotobuf.set_name("wang");
		myprotobuf.set_id(2);
		myprotobuf.set_email("[email protected]");

		//protobuf的序列化方式之一
		memset(buff,0,BUFFSIZE);
		myprotobuf.SerializeToArray(buff,BUFFSIZE);
	
		if(send(socketfd,buff,strlen(buff),0) < 0)
		{
			cout<<curtime<<": send failed ..."<<endl;
			break;
		}
		cout<<curtime<<": send success ..."<<endl;
		
		Sleep(3000);    //每隔3s發送一次
	}
	closesocket(socketfd);
	WSACleanup();       //釋放套接字資源  

	return 0;
}

// 服務端程序
#pragma 
#include "stdafx.h"
#include <winsock2.h>
#include <stdio.h>
#include <cstdio>  
#include <iostream>
#include <string>
#include <ctime>
#include "people.pb.h"

#pragma comment( lib, "ws2_32.lib")

using namespace std;
using namespace PeopleT::Test;

const int BUFFSIZE = 128;
const int QLEN = 10 ;

int _tmain(int argc, char* argv[])
{

	WSADATA         wsd;            //WSADATA變量  
	SOCKET     listenfd;            //服務器套接字 
	int          connfd;            //客戶端套接字  
	struct sockaddr_in seraddr ;    //服務器地址


	//初始化套結字動態庫  
	if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)  
	{
		cout << "WSAStartup failed!" << endl;  
		return -1;  
	}

	//建立socket
	//AF_INET:IPv4因特網域
	//SOCK_STREAM:TCP鏈接
	//0:給定前兩個參數,選擇默認的協議
	listenfd = socket(AF_INET,SOCK_STREAM,0);
	if(listenfd < 0 )
	{
		cout<<"socket failed"<<endl;
		WSACleanup();//釋放套接字資源;  
		return -1;
	}

	//地址置空
	memset(&seraddr,sizeof(seraddr),0);
	//服務器套接字地址   
	seraddr.sin_family = AF_INET ;
	seraddr.sin_port = htons(9999);
	seraddr.sin_addr.s_addr = htonl(INADDR_ANY);
	//關聯地址和套接字
	if(bind(listenfd,(struct sockaddr *)&seraddr, sizeof(seraddr)) < 0)
	{
		cout<<"bind address with socket failed..."<<endl;
		closesocket(listenfd);
		WSACleanup();  //釋放套接字資源;  
		return -1;
	}

	//調用listen,宣告server願意接受鏈接請求 : 開始監聽
	if(listen(listenfd,QLEN) == INVALID_SOCKET   )
	{
		cout<<"listen on socket failed..."<<endl;
		closesocket(listenfd);
		WSACleanup();  //釋放套接字資源
		return -1;
	}

	//獲得連接請求,並建立連接
	if( (connfd = accept(listenfd,(struct sockaddr *)NULL,NULL)) < 0 )
	{
		cout<<"accept the request failed"<<endl;
		closesocket(listenfd);
		WSACleanup();  //釋放套接字資源
		return -1;
	}

	People  myprotobuf;
	char buff[BUFFSIZE];
	while( true )
	{
		if(recv(connfd,buff,sizeof(buff),0) < 0)
		{
			cout<<"recv failed ..."<<endl;
			break;
		}
		//protobuf反序列化
		myprotobuf.ParseFromArray(buff,BUFFSIZE);
		cout<<"name :"<<myprotobuf.name()<<"\n"
			<<"id :"<<myprotobuf.id()<<"\n"
			<<"email :"<<myprotobuf.email()<<endl;
		memset(buff,0,BUFFSIZE);
	}
	closesocket(listenfd);
	closesocket(connfd);
	WSACleanup();  //釋放套接字資源

	return 0;

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章