VS下使用Google Protobuf完成SOCKET通信
如何在Windows环境下的VS中安装使用Google Protobuf完成SOCKET通信
出处:如何在Windows环境下的VS中安装使用Google Protobuf完成SOCKET通信
最近一段时间,由于项目的需要,接触到了Protobuf这个东东,在Linux环境下,体验了一把,感觉挺不错,很方便,且高效。是一个非常值得学习掌握和应用的数据抽象、平台无关、功能强大、…(此处省略1000字)的开源工具。
Google虽然把Protobuf做成了跨平台、跨语言,但作为微软的死对头,它在readme.txt文件的第一句话就表明了态度:为了考虑部分MSVC的用户,Protobuf提供了针对VS的安装说明,但Protobuf最好用于Unix环境下。
在上一篇博客中,我介绍了如何在Linux环境下安装Protobuf,现在让我们了解一下Windows环境下,如何在VS中使用Protobuf,注意是VS,在VC6的环境下,我搞弄了一个晚上都没成功,所以推荐VS2005或者以上版本:
1.下载protobuff,我下的是2.3.0版本
最新的protobuf可以到Google Code上下载:http://code.google.com/p/protobuf/downloads/list
当前版本为2.3.0,下载两个压缩包:protoc-2.3.0-win32.zip和protobuf-2.3.0.zip,前者是protobuf的编译器,后者包含了有三程序语言的开发包。
2.解压
首先解压protoc-2.3.0-win32.zip,把protoc.exe文件放到path路径中,最简单的做法就是把这个文件拷贝到C:/WINDOWS目录下。
解压protobuf-2.3.0.zip文件,将文件加压到C盘根目录,主文件位于C:/protobuf-2.3.0/protobuf-2.3.0目录下。
3.安装操作
(1)使用VS2005编译proto,VS工程目录位于vsprojects目录中,工程名字为“protobuf.sln”。
(2)选择“生成”à“生成解决方案”选项进行编译,编译过程中可能会由于编译的顺序报错误,可以使用手工逐个顺序编译生成,可能会比较顺利。按照下图的顺序,右键“重新生成”,逐个编译。但是我在实习操作过程中,libprotobuf-lite工程重来都没有成功编译通过过。淡定先,这个不会影响大局的。
(3)编译完成会在目录vsprojects下的Debug目录中生成lib和exe文件。
生成清单如下:
exe文件:
2010-04-15 09:51 950,272 lite-test.exe
2010-04-15 09:50 3,219,456 protoc.exe
2010-04-15 09:48 9,228,288 tests.exe
2010-04-15 09:56 2,519,040 test_plugin.exe
lib文件:
2010-04-15 09:50 2,685,922 libprotobuf-lite.lib
2010-04-15 09:56 24,100,794 libprotobuf.lib
2010-04-15 09:56 17,302,068 libprotoc.lib
其实我在测试过程中,lite-test.exe和libprotobuf-lite.lib并没有生成,因为编译错误了,但这并不影响大局,淡定先。
(4)OK,至此,我们已经完成了编译工作,下面需要进行的是protobuf的测试。我们需要使用到之前VS编译出来的libprotobuf.lib和libprotoc.lib完成一个C/S结构的SOCKET通信测试。
àProtobuf的测试
在VS2005下,创建两个新的工程,分别命名为server和client,每个工程都需要引用protobuf的头文件和lib文件。
一、添加protobuf头文件操作:右击项目à属性à配置属性àC/C++à常规 (也命令行可在中添加)。具体路径:C:/protobuf-2.3.0/protobuf-2.3.0/src
二、添加protobuf的lib文件操作:右击项目à属性à配置属性à链接器à常规(也可在命令行中添加)。具体路径:C:/protobuf-2.3.0/protobuf-2.3.0/vsprojects/Debug
三、CMD窗口下编译生成头文件:
C:/protobuf-2.3.0/protobuf-2.3.0/examples>protoc -I=./ --cpp_out=./ people.proto
将proto文件生成的文件放到当前目录。
我们得到了两个文件生:people.pb.h和people.pb.cc
people.proto文件内容如下:
- package CPFS;
- message People
- {
- required string name = 1;
- required int32 id = 2;
- required string email = 3;
- }
四、server和client端源代码:
server端源代码:
- #include "common/op_socket.h"
- #include "people.pb.h"
- #pragma comment(lib, "libprotobuf.lib")
- #pragma comment(lib, "libprotoc.lib")
- using namespace std;
- int main()
- {
- GOOGLE_PROTOBUF_VERIFY_VERSION;
- OP_SOCKET server_sockfd;
- OP_SOCKET new_server_sockfd;
- OP_SOCKADDR_IN server_addr;
- OP_SOCKADDR_IN client_addr;
- OP_SOCKLEN_T sin_size;
- char buffer[BUFFER_SIZE + 1];
- int bytes;
- string str;
- string data;
- CPFS::People p;
- #ifdef WIN32
- WSADATA Ws;
- //Init Windows Socket
- if (WSAStartup(MAKEWORD(2,2), &Ws) != 0)
- {
- fprintf(stderr, "Init Windows Socket Failed::%s", GetLastError());
- return EXIT_FAILURE;
- }
- #endif
- server_sockfd = op_socket(AF_INET, SOCK_STREAM, 0);
- op_set_sockaddr_in(server_addr, AF_INET, htons(INADDR_ANY), htons(OP_PORT));
- op_bind(server_sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));
- op_listen(server_sockfd, LISTEN_QUEUE);
- while(1)
- {
- sin_size = sizeof(struct sockaddr_in);
- new_server_sockfd = op_accept(server_sockfd, (struct sockaddr *)&client_addr, &sin_size);
- bytes = op_recv(new_server_sockfd, buffer, BUFFER_SIZE, 0);
- buffer[bytes] = '/0';
- str = buffer;
- cout << "You got a message from " << inet_ntoa(client_addr.sin_addr) << endl;
- cout << "client_addr Message: " << str << endl;
- if(str == "get")
- {
- p.set_id(1);
- p.set_name("monkey");
- p.set_email("mokeydong@gmail.com");
- p.SerializeToString(&data);
- char dst[BUFFER_SIZE];
- strcpy(dst, data.c_str());
- op_send(new_server_sockfd, dst, sizeof(dst), 0);
- }
- else
- {
- op_send(new_server_sockfd, "Fucking client_addr!/n", 16, 0);
- }
- op_close(new_server_sockfd);
- }
- op_close(server_sockfd);
- google::protobuf::ShutdownProtobufLibrary();
- getchar();
- #ifdef WIN32
- WSACleanup();
- #endif
- return EXIT_SUCCESS;
- }
client源代码:
- #include "common/op_socket.h"
- #include "people.pb.h"
- #pragma comment(lib, "libprotobuf.lib")
- #pragma comment(lib, "libprotoc.lib")
- using namespace std;
- int main(int argc, char **argv)
- {
- GOOGLE_PROTOBUF_VERIFY_VERSION;
- OP_SOCKET client_sockfd;
- OP_SOCKADDR_IN server_addr;
- OP_SOCKADDR_IN client_addr;
- char buffer[BUFFER_SIZE + 1];
- int bytes;
- CPFS::People p;
- if (argc != 2)
- {
- printf("Usage: %s /"COMMAND/"/n",argv[0]);
- exit(0);
- }
- #ifdef WIN32
- WSADATA Ws;
- //Init Windows Socket
- if (WSAStartup(MAKEWORD(2,2), &Ws) != 0)
- {
- fprintf(stderr, "Init Windows Socket Failed::%s", GetLastError());
- return EXIT_FAILURE;
- }
- #endif
- client_sockfd = op_socket(AF_INET, SOCK_STREAM, 0);
- op_set_sockaddr_in(server_addr, AF_INET, op_inet_addr(DEFAULT_SERVER_IP), htons(OP_PORT));
- op_connect(client_sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));
- op_send(client_sockfd, argv[1], 20, 0);
- bytes = op_recv(client_sockfd, buffer, BUFFER_SIZE, 0);
- buffer[bytes] = '/0';
- string data = buffer;
- p.ParseFromString(data);
- cout << "Name: " << p.name() << endl;
- cout << "ID: " << p.id() << endl;
- cout << "Email: " << p.email() << endl;
- op_close(client_sockfd);
- #ifdef WIN32
- WSACleanup();
- #endif
- google::protobuf::ShutdownProtobufLibrary();
- return EXIT_SUCCESS;
- }
五、因为上述两个代码用到了我写了一个初级版本的SOCKET跨平台的库,这里贴出来,很龊,但还可以用,小弟也才开始写socket程序。这个库文件要放到common/目录下面。
op_socket.h源代码:
- #ifndef OP_SOCKET_H_
- #define OP_SOCKET_H_
- #include <stdio.h>
- #include <errno.h>
- #include <string.h>
- #include <stdlib.h>
- #include <iostream>
- #include <string>
- #ifndef WIN32
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <sys/socket.h>
- #include <arpa/inet.h>
- #include <netinet/in.h>
- #include <signal.h>
- #include <netdb.h>
- #include <unistd.h>
- #include <fcntl.h>
- #else
- #include <winsock2.h>
- #pragma comment(lib, "ws2_32.lib")
- #endif
- // Linux
- #ifndef WIN32
- #define OP_SOCKET int
- #define OP_SOCKADDR_IN struct sockaddr_in
- #define OP_SOCKADDR struct sockaddr
- #define OP_SOCKLEN_T socklen_t
- // Windows
- #else
- #define OP_SOCKET SOCKET
- #define OP_SOCKADDR_IN SOCKADDR_IN
- #define OP_SOCKADDR SOCKADDR
- #define OP_SOCKLEN_T int FAR
- #endif
- #define OP_PORT 8888
- #define BUFFER_SIZE 1024
- #define LISTEN_QUEUE 20
- #define MD5_SIZE 32
- #define FILE_PATH_MAX_SIZE 512
- #define FILE_NAME_MAX_SIZE 260
- #define FILE_FULL_NAME_MAX_SIZE 1024
- #define HOST "localhost"
- #define DEFAULT_SERVER_IP "127.0.0.1"
- #ifndef WIN32
- #define CLI_FILE_PATH "/tmp/data/client/" // 客户端存储文件的初始化路径
- #define SERV_FILE_PATH "/tmp/data/server/" // 服务器端存储文件的初始化路径
- #else
- #define CLI_FILE_PATH "D://download//" // 客户端存储文件的初始化路径
- #define SERV_FILE_PATH "D://data//" // 客户端存储文件的初始化路径
- #endif
- // 把一段内存区的内容全部设置为
- void op_clean_buffer(void *buffer, int len);
- // 设置sockaddr_in, internet协议族, INADDR_ANY表示自动获取本机地址
- void op_set_sockaddr_in(OP_SOCKADDR_IN &addr, short op_sin_family, unsigned long op_s_addr, unsigned short op_sin_port);
- // 创建用于internet的流协议(TCP)socket, 用server_socket代表服务器socket
- int op_socket(int domain, int type, int protocol);
- // 接受一个到server_socket代表的socket的一个连接
- // 如果没有连接请求,就等待到有连接请求--这是accept函数的特性
- // accept函数返回一个新的socket, 这个socket(new_server_socket)用于同连接到的客户的通信
- // new_server_socket代表了服务器和客户端之间的一个通信通道
- // accept函数把连接到的客户端信息填写到客户端的socket地址结构client_addr中
- int op_accept(OP_SOCKET sockfd, OP_SOCKADDR *addr, OP_SOCKLEN_T *addrlen);
- // IP的点分十记转化为IP的结构体
- unsigned long op_inet_addr(const char *dst);
- // 向服务器发起连接,连接成功后client_socket代表了客户机和服务器的一个socket连接
- int op_connect(OP_SOCKET sockfd, const OP_SOCKADDR *addr, OP_SOCKLEN_T addrlen);
- // addr指定的地址分配给与文件描述符socket关联的未命名套接字
- int op_bind(OP_SOCKET sockfd, const OP_SOCKADDR *addr, OP_SOCKLEN_T addrlen);
- // 监听client请求,backlog指定最大连接数
- int op_listen(OP_SOCKET sockfd, int backlog);
- // send发送消息
- int op_send(OP_SOCKET sockfd, const char *buffer, size_t len, int flags);
- // recv接收消息
- int op_recv(OP_SOCKET sockfd, char *buffer, size_t len, int flags);
- // 关闭socket或文件指针
- FILE* op_fopen(const char *path, const char *mode);
- // 打开文件
- int op_close(OP_SOCKET sockfd);
- // 关闭文件指针
- int op_fclose(FILE *stream);
- // 休眠函数
- void op_sleep(int micro_seconds);
- // 字符串比较函数
- int op_stricmp(char *s1,char * s2);
- #endif
op_socket.cpp源文件代码:
- #include "op_socket.h"
- // 把一段内存区的内容全部设置为
- void op_clean_buffer(void *buffer, int len)
- {
- #ifndef WIN32
- bzero(buffer, len);
- #else
- memset(buffer, 0, len);
- #endif
- }
- // 设置sockaddr_in
- void op_set_sockaddr_in(OP_SOCKADDR_IN &addr, short op_sin_family, unsigned long op_s_addr, unsigned short op_sin_port)
- {
- op_clean_buffer(&addr, sizeof(addr));
- addr.sin_family = op_sin_family;
- addr.sin_addr.s_addr = op_s_addr;
- addr.sin_port = op_sin_port;
- }
- // 创建socket
- int op_socket(int domain, int type, int protocol)
- {
- int sockfd;
- #ifndef WIN32
- if ((sockfd = socket(domain, type, protocol)) < 0)
- #else
- if ((sockfd = socket(domain, type, protocol)) == INVALID_SOCKET)
- #endif
- {
- fprintf(stderr, "op_socket error/n");
- exit(EXIT_FAILURE);
- }
- return sockfd;
- }
- // 接收客户端的socket请求
- int op_accept(OP_SOCKET sockfd, OP_SOCKADDR *addr, OP_SOCKLEN_T *addrlen)
- {
- int ret;
- if ((ret = accept(sockfd, addr, addrlen)) < 0)
- {
- fprintf(stderr, "op_accept error/n");
- exit(EXIT_FAILURE);
- }
- return ret;
- }
- // IP的点分十记转化为IP的结构体
- unsigned long op_inet_addr(const char *dst)
- {
- long ret;
- if ((ret = inet_addr(dst)) < 0)
- {
- fprintf(stderr, "op_inet_addr error for %s/n", dst);
- exit(EXIT_FAILURE);
- }
- return (unsigned long)ret;
- }
- // sockfd指定的套接字连接到addr指定的服务器套接字
- int op_connect(OP_SOCKET sockfd, const OP_SOCKADDR *addr, OP_SOCKLEN_T addrlen)
- {
- int ret;
- if ((ret = connect(sockfd, addr, addrlen)) < 0)
- {
- fprintf(stderr, "op_connect error/n");
- exit(EXIT_FAILURE);
- }
- return ret;
- }
- // addr指定的地址分配给与文件描述符socket关联的未命名套接字
- int op_bind(OP_SOCKET sockfd, const OP_SOCKADDR *addr, OP_SOCKLEN_T addrlen)
- {
- int ret;
- if ((ret = bind(sockfd, addr, addrlen)) < 0)
- {
- fprintf(stderr, "op_bind error/n");
- exit(EXIT_FAILURE);
- }
- return ret;
- }
- // 监听client请求,backlog指定最大连接数
- int op_listen(OP_SOCKET sockfd, int backlog)
- {
- int ret;
- if ((ret = listen(sockfd, backlog)) < 0)
- {
- fprintf(stderr, "op_listen error/n");
- exit(EXIT_FAILURE);
- }
- return ret;
- }
- // send发送消息
- int op_send(OP_SOCKET sockfd, const char *buffer, size_t len, int flags)
- {
- int ret;
- if ((ret = send(sockfd, buffer, len, flags)) < 0)
- {
- fprintf(stderr, "op_send error/n");
- exit(EXIT_FAILURE);
- }
- return ret;
- }
- // recv接收消息
- int op_recv(OP_SOCKET sockfd, char *buffer, size_t len, int flags)
- {
- size_t ret;
- op_clean_buffer(buffer, len);
- if ((ret = recv(sockfd, buffer, len, flags)) < 0)
- {
- fprintf(stderr, "op_recv error/n");
- exit(EXIT_FAILURE);
- }
- return ret;
- }
- // 关闭socket或文件指针
- int op_close(OP_SOCKET sockfd)
- {
- int ret;
- #ifndef WIN32
- if ((ret = close(sockfd)) < 0)
- #else
- if((ret = closesocket(sockfd)) < 0)
- #endif
- {
- fprintf(stderr, "op_close error/n");
- exit(EXIT_FAILURE);
- }
- return ret;
- }
- // 打开文件
- FILE* op_fopen(const char *path, const char *mode)
- {
- FILE *fp = fopen(path, mode);
- if (NULL == fp)
- {
- printf("File:/t%s Can Not Open To Write/n", path);
- exit(EXIT_FAILURE);
- }
- return fp;
- }
- // 关闭文件指针
- int op_fclose(FILE *stream)
- {
- int ret;
- if ((ret = fclose(stream)) < 0)
- {
- fprintf(stderr, "op_fclose error/n");
- exit(EXIT_FAILURE);
- }
- return ret;
- }
- // 休眠函数,对于usleep为微秒级别,对于Sleep为毫秒级别
- void op_sleep(int micro_seconds)
- {
- #ifndef WIN32
- usleep(micro_seconds);
- #else
- Sleep(micro_seconds);
- #endif
- }
- // 字符串比较函数
- int op_stricmp(char *s1,char * s2)
- {
- #ifndef WIN32
- return strcasecmp(s1, s2);
- #else
- return stricmp(s1, s2);
- #endif
- }
六、完成了上述的操作之后,就可以分别对client和server端进行编译了,先启动server端服务器,然后用命令行的形式运行client端,就可以成功了吧。哈哈!我们来看一下使用protobuf进行socket通信的实际效果!给大家截个图!
VS下使用Google Protobuf完成SOCKET通信的更多相关文章
- 在C语言环境下使用google protobuf
本文写给经常使用C编程且不喜欢C++而又要经常使用google protobuf的人. 经常写通讯程序的人对数据进行序列化或者反序列化时,可能经常使用google的protobuf(PB ...
- Windows下编译Google.Protobuf在Qt(C++)中使用与Unity3d(C#)交互
1.首先从Github-Protobuf下载代码,本文下载的版本号是3.1.0. 2.仔细查看各个README,有相关的资源下载和编译说明. 3.在一个方便的地方创建一个Install类型的文件夹,放 ...
- Linux环境下用C语言实现socket 通信---简单代码
Socket编程实例: 服务器端:一直监听本机的8000号端口,如果收到连接请求,将接收请求并接收客户端发来的消息,并向客户端返回消息. 客户端:client.c /* File Name: clie ...
- window下编译并使用google protobuf
参考网址: http://my.oschina.net/chenleijava/blog/261263 http://www.ibm.com/developerworks/cn/linux/l-cn- ...
- Linux下简单的socket通信实例
Linux下简单的socket通信实例 If you spend too much time thinking about a thing, you’ll never get it done. —Br ...
- windows下用c实现Socket通信
原文:windows下用c实现Socket通信 原本以为c是跨平台,所以,c在windows下和linux下的程序应该是类似于Java,什么都不用改变的,今儿才恍然大悟,他们的类库不一样啊-- 下面我 ...
- Windows环境下google protobuf入门
我使用的是最新版本的protobuf(protobuf-2.6.1),编程工具使用VS2010.简单介绍下google protobuf: google protobuf 主要用于通讯,是google ...
- google protobuf VC下的使用笔记
1 使用protobuf 2.x 下载地址(3.x 在c++11 vs2017下报错) 源码 https://github.com/google/protobuf 或者直接下载 二进制文件 2 如果下 ...
- Linux 下socket通信终极指南(附TCP、UDP完整代码)
linux下用socket通信,有TCP.UDP两种协议,网上的很多教程把两个混在了一起,或者只讲其中一种.现在我把自己这两天研究的成果汇总下来,写了一个完整的,适合初学者参考,也方便自己以后查阅. ...
随机推荐
- BottomSheet底部动作条使用
底部动作条 底部动作条(Bottom Sheets)是一个从屏幕底部边缘向上滑出的一个面板,使用这种方式向用户呈现一组功能.底部动作条呈现了简单.清晰.无需额外解释的一组操作. 使用环境 底部动作条( ...
- C++ Primer 有感(命名的强制类型转换)
C++四种强制类型转换的方法以及其应用场合,之前有看过这个知识点,但是,面试的时候怎么想也就没有写的很全面,于是,这里整理一下: C++中的四种强制类型转换除了具有C语言强制类型转换的功能外,还可提供 ...
- android升级后错误:Unable to execute dex: java.nio.BufferOverflowException.Check
Android SDK Tools升级为22.3,Android SDK Platform-tools 升级为19后,编译工程出现错误: Unable to execute dex: java.nio ...
- 【UML 建模】UML建模语言入门 -- 静态图详解 类图 对象图 包图 静态图建模实战
发现个好东西思维导图, 最近开始用MindManager整理博客 . 作者 :万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/deta ...
- 关于精灵帧(Sprite Frame)的尺寸大小
一个对象的精灵帧(Sprite Frame)有若干关于大小的尺寸. 比较容易混淆,这里记录下来区别: CCSpriteFrame *spriteFrame = self.spriteFrame; CG ...
- Hadoop家族
现在Hadoop家族产品,已经达到20个了之多. 有必要对自己的知识做一个整理了,把产品和技术都串起来.不仅能加深印象,更可以对以后的技术方向,技术选型做好基础准备. 本文为"Hadoop家 ...
- OpenCV实现仿射变换
什么是仿射变换?¶ 一个任意的仿射变换都能表示为 乘以一个矩阵 (线性变换) 接着再 加上一个向量 (平移). 综上所述, 我们能够用仿射变换来表示: 旋转 (线性变换) 平移 (向量加) 缩放操作 ...
- LeetCode之“动态规划”:Dungeon Game
题目链接 题目要求: The demons had captured the princess (P) and imprisoned her in the bottom-right corner of ...
- Socket层实现系列 — accept()的实现(二)
本文主要分析accept()的阻塞等待和唤醒. 内核版本:3.6 Author:zhangskd @ csdn blog 等待队列 (1)socket的等待队列 /* * @sk_wq: sock w ...
- Linux IPC - Shared memory
http://blog.163.com/muren20062094@yeah/blog/static/161844416201161974646434/ 1. Create shared memory ...