如何在Windows环境下的VS中安装使用Google Protobuf完成SOCKET通信
2010-09-19 16:29
726 查看
如何在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文件内容如下:
四、server和client端源代码:
server端源代码:
client源代码:
五、因为上述两个代码用到了我写了一个初级版本的SOCKET跨平台的库,这里贴出来,很龊,但还可以用,小弟也才开始写socket程序。这个库文件要放到common/目录下面。
op_socket.h源代码:
op_socket.cpp源文件代码:
六、完成了上述的操作之后,就可以分别对client和server端进行编译了,先启动server端服务器,然后用命令行的形式运行client端,就可以成功了吧。哈哈!我们来看一下使用protobuf进行socket通信的实际效果!给大家截个图!
最近项目紧,没空时间来好好写博客,只能粗略记录一下,等实习结束后,要把这段时间的所学所感好好总结下来。
顺便说一下,op_socket这个SOCKET是跨平台的,写个makefile可以直接在UNIX环境下运行的,咳咳,写的太龊了大家见笑了。。。
最近一段时间,由于项目的需要,接触到了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通信的实际效果!给大家截个图!
最近项目紧,没空时间来好好写博客,只能粗略记录一下,等实习结束后,要把这段时间的所学所感好好总结下来。
顺便说一下,op_socket这个SOCKET是跨平台的,写个makefile可以直接在UNIX环境下运行的,咳咳,写的太龊了大家见笑了。。。
相关文章推荐
- 如何在Windows环境下的VS中安装使用Google Protobuf完成SOCKET通信
- 如何在Windows环境下的VS中安装使用Google Protobuf完成SOCKET通信
- 如何在Windows环境下的VS中安装使用Google Protobuf完成SOCKET通信
- 如何在Windows环境下的VS中安装使用Google Protobuf完成SOCKET通信
- 如何在Windows环境下的VS中安装使用Google Protobuf完成socket通信
- 如何在Windows环境下的VS中安装使用Google Protobuf完成SOCKET通信
- 如何在Windows环境下的VS中安装使用Google Protobuf完成SOCKET通信
- 如何在Windows环境下安装OpenCV,并且在Microsoft Visual Studio 2010中使用OpenCV编写应用程序
- 如何在Windows平台使用VS搭建C++/Lua的开发环境
- Windows 10 VS2015 环境下安装使用BLAS线性代数库
- 如何在 windows 10 环境下 使用 composer 安装 laravel
- 如何在Windows平台使用VS搭建C++/Lua的开发环境
- 如何在Windows平台使用VS搭建C++/Lua的开发环境
- VS下使用Google Protobuf完成SOCKET通信
- 如何在Windows平台使用VS搭建C++/Lua的开发环境
- 如何在Linux环境下在CodeBlock中安装使用Google Protobuf
- 在没有安装VS的windows系统中,如何运行eXtremeDB
- 《Swift入门》如何在Windows或者ubuntu下安装XCode6环境来开发Swift?
- Appium基础篇1-如何在windows上安装Appium环境