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文件内容如下:

[cpp] view plaincopy

  1. package CPFS;
  2. message People
  3. {
  4. required string name = 1;
  5. required int32 id = 2;
  6. required string email = 3;
  7. }

四、server和client端源代码:

server端源代码:

[cpp] view plaincopy

  1. #include "common/op_socket.h"
  2. #include "people.pb.h"
  3. #pragma comment(lib, "libprotobuf.lib")
  4. #pragma comment(lib, "libprotoc.lib")
  5. using namespace std;
  6. int main()
  7. {
  8. GOOGLE_PROTOBUF_VERIFY_VERSION;
  9. OP_SOCKET server_sockfd;
  10. OP_SOCKET new_server_sockfd;
  11. OP_SOCKADDR_IN server_addr;
  12. OP_SOCKADDR_IN client_addr;
  13. OP_SOCKLEN_T sin_size;
  14. char buffer[BUFFER_SIZE + 1];
  15. int bytes;
  16. string str;
  17. string data;
  18. CPFS::People p;
  19. #ifdef WIN32
  20. WSADATA  Ws;
  21. //Init Windows Socket
  22. if (WSAStartup(MAKEWORD(2,2), &Ws) != 0)
  23. {
  24. fprintf(stderr, "Init Windows Socket Failed::%s", GetLastError());
  25. return EXIT_FAILURE;
  26. }
  27. #endif
  28. server_sockfd = op_socket(AF_INET, SOCK_STREAM, 0);
  29. op_set_sockaddr_in(server_addr, AF_INET, htons(INADDR_ANY), htons(OP_PORT));
  30. op_bind(server_sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));
  31. op_listen(server_sockfd, LISTEN_QUEUE);
  32. while(1)
  33. {
  34. sin_size = sizeof(struct sockaddr_in);
  35. new_server_sockfd = op_accept(server_sockfd, (struct sockaddr *)&client_addr, &sin_size);
  36. bytes = op_recv(new_server_sockfd, buffer, BUFFER_SIZE, 0);
  37. buffer[bytes] = ‘/0‘;
  38. str = buffer;
  39. cout << "You got a message from " << inet_ntoa(client_addr.sin_addr) << endl;
  40. cout << "client_addr Message: " << str << endl;
  41. if(str == "get")
  42. {
  43. p.set_id(1);
  44. p.set_name("monkey");
  45. p.set_email("[email protected]");
  46. p.SerializeToString(&data);
  47. char dst[BUFFER_SIZE];
  48. strcpy(dst, data.c_str());
  49. op_send(new_server_sockfd, dst, sizeof(dst), 0);
  50. }
  51. else
  52. {
  53. op_send(new_server_sockfd, "Fucking client_addr!/n", 16, 0);
  54. }
  55. op_close(new_server_sockfd);
  56. }
  57. op_close(server_sockfd);
  58. google::protobuf::ShutdownProtobufLibrary();
  59. getchar();
  60. #ifdef WIN32
  61. WSACleanup();
  62. #endif
  63. return EXIT_SUCCESS;
  64. }

client源代码:

[cpp] view plaincopy

  1. #include "common/op_socket.h"
  2. #include "people.pb.h"
  3. #pragma comment(lib, "libprotobuf.lib")
  4. #pragma comment(lib, "libprotoc.lib")
  5. using namespace std;
  6. int main(int argc, char **argv)
  7. {
  8. GOOGLE_PROTOBUF_VERIFY_VERSION;
  9. OP_SOCKET client_sockfd;
  10. OP_SOCKADDR_IN server_addr;
  11. OP_SOCKADDR_IN client_addr;
  12. char buffer[BUFFER_SIZE + 1];
  13. int bytes;
  14. CPFS::People p;
  15. if (argc != 2)
  16. {
  17. printf("Usage: %s /"COMMAND/"/n",argv[0]);
  18. exit(0);
  19. }
  20. #ifdef WIN32
  21. WSADATA  Ws;
  22. //Init Windows Socket
  23. if (WSAStartup(MAKEWORD(2,2), &Ws) != 0)
  24. {
  25. fprintf(stderr, "Init Windows Socket Failed::%s", GetLastError());
  26. return EXIT_FAILURE;
  27. }
  28. #endif
  29. client_sockfd = op_socket(AF_INET, SOCK_STREAM, 0);
  30. op_set_sockaddr_in(server_addr, AF_INET, op_inet_addr(DEFAULT_SERVER_IP), htons(OP_PORT));
  31. op_connect(client_sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));
  32. op_send(client_sockfd, argv[1], 20, 0);
  33. bytes = op_recv(client_sockfd, buffer, BUFFER_SIZE, 0);
  34. buffer[bytes] = ‘/0‘;
  35. string data = buffer;
  36. p.ParseFromString(data);
  37. cout << "Name: " << p.name() << endl;
  38. cout << "ID: " << p.id() << endl;
  39. cout << "Email: " << p.email() << endl;
  40. op_close(client_sockfd);
  41. #ifdef WIN32
  42. WSACleanup();
  43. #endif
  44. google::protobuf::ShutdownProtobufLibrary();
  45. return EXIT_SUCCESS;
  46. }

五、因为上述两个代码用到了我写了一个初级版本的SOCKET跨平台的库,这里贴出来,很龊,但还可以用,小弟也才开始写socket程序。这个库文件要放到common/目录下面。

op_socket.h源代码:

[cpp] view plaincopy

  1. #ifndef OP_SOCKET_H_
  2. #define OP_SOCKET_H_
  3. #include <stdio.h>
  4. #include <errno.h>
  5. #include <string.h>
  6. #include <stdlib.h>
  7. #include <iostream>
  8. #include <string>
  9. #ifndef WIN32
  10. #include <sys/types.h>
  11. #include <sys/wait.h>
  12. #include <sys/socket.h>
  13. #include <arpa/inet.h>
  14. #include <netinet/in.h>
  15. #include <signal.h>
  16. #include <netdb.h>
  17. #include <unistd.h>
  18. #include <fcntl.h>
  19. #else
  20. #include <winsock2.h>
  21. #pragma comment(lib, "ws2_32.lib")
  22. #endif
  23. // Linux
  24. #ifndef WIN32
  25. #define OP_SOCKET               int
  26. #define OP_SOCKADDR_IN          struct sockaddr_in
  27. #define OP_SOCKADDR             struct sockaddr
  28. #define OP_SOCKLEN_T            socklen_t
  29. // Windows
  30. #else
  31. #define OP_SOCKET               SOCKET
  32. #define OP_SOCKADDR_IN          SOCKADDR_IN
  33. #define OP_SOCKADDR             SOCKADDR
  34. #define OP_SOCKLEN_T            int FAR
  35. #endif
  36. #define OP_PORT                     8888
  37. #define BUFFER_SIZE                 1024
  38. #define LISTEN_QUEUE                20
  39. #define MD5_SIZE                    32
  40. #define FILE_PATH_MAX_SIZE          512
  41. #define FILE_NAME_MAX_SIZE          260
  42. #define FILE_FULL_NAME_MAX_SIZE     1024
  43. #define HOST                        "localhost"
  44. #define DEFAULT_SERVER_IP           "127.0.0.1"
  45. #ifndef WIN32
  46. #define CLI_FILE_PATH           "/tmp/data/client/" // 客户端存储文件的初始化路径
  47. #define SERV_FILE_PATH          "/tmp/data/server/" // 服务器端存储文件的初始化路径
  48. #else
  49. #define CLI_FILE_PATH           "D://download//"    // 客户端存储文件的初始化路径
  50. #define SERV_FILE_PATH          "D://data//"        // 客户端存储文件的初始化路径
  51. #endif
  52. // 把一段内存区的内容全部设置为
  53. void op_clean_buffer(void *buffer, int len);
  54. // 设置sockaddr_in, internet协议族, INADDR_ANY表示自动获取本机地址
  55. void op_set_sockaddr_in(OP_SOCKADDR_IN &addr, short op_sin_family, unsigned long op_s_addr, unsigned short op_sin_port);
  56. // 创建用于internet的流协议(TCP)socket, 用server_socket代表服务器socket
  57. int op_socket(int domain, int type, int protocol);
  58. // 接受一个到server_socket代表的socket的一个连接
  59. // 如果没有连接请求,就等待到有连接请求--这是accept函数的特性
  60. // accept函数返回一个新的socket, 这个socket(new_server_socket)用于同连接到的客户的通信
  61. // new_server_socket代表了服务器和客户端之间的一个通信通道
  62. // accept函数把连接到的客户端信息填写到客户端的socket地址结构client_addr中
  63. int op_accept(OP_SOCKET sockfd, OP_SOCKADDR *addr, OP_SOCKLEN_T *addrlen);
  64. // IP的点分十记转化为IP的结构体
  65. unsigned long op_inet_addr(const char *dst);
  66. // 向服务器发起连接,连接成功后client_socket代表了客户机和服务器的一个socket连接
  67. int op_connect(OP_SOCKET sockfd, const OP_SOCKADDR *addr, OP_SOCKLEN_T addrlen);
  68. // addr指定的地址分配给与文件描述符socket关联的未命名套接字
  69. int op_bind(OP_SOCKET sockfd, const OP_SOCKADDR *addr, OP_SOCKLEN_T addrlen);
  70. // 监听client请求,backlog指定最大连接数
  71. int op_listen(OP_SOCKET sockfd, int backlog);
  72. // send发送消息
  73. int op_send(OP_SOCKET sockfd, const char *buffer, size_t len, int flags);
  74. // recv接收消息
  75. int op_recv(OP_SOCKET sockfd, char *buffer, size_t len, int flags);
  76. // 关闭socket或文件指针
  77. FILE* op_fopen(const char *path, const char *mode);
  78. // 打开文件
  79. int op_close(OP_SOCKET sockfd);
  80. // 关闭文件指针
  81. int op_fclose(FILE *stream);
  82. // 休眠函数
  83. void op_sleep(int micro_seconds);
  84. // 字符串比较函数
  85. int op_stricmp(char *s1,char * s2);
  86. #endif

op_socket.cpp源文件代码:

[cpp] view plaincopy

  1. #include "op_socket.h"
  2. // 把一段内存区的内容全部设置为
  3. void op_clean_buffer(void *buffer, int len)
  4. {
  5. #ifndef WIN32
  6. bzero(buffer, len);
  7. #else
  8. memset(buffer, 0, len);
  9. #endif
  10. }
  11. // 设置sockaddr_in
  12. void op_set_sockaddr_in(OP_SOCKADDR_IN &addr, short op_sin_family, unsigned long op_s_addr, unsigned short op_sin_port)
  13. {
  14. op_clean_buffer(&addr, sizeof(addr));
  15. addr.sin_family = op_sin_family;
  16. addr.sin_addr.s_addr = op_s_addr;
  17. addr.sin_port = op_sin_port;
  18. }
  19. // 创建socket
  20. int op_socket(int domain, int type, int protocol)
  21. {
  22. int sockfd;
  23. #ifndef WIN32
  24. if ((sockfd = socket(domain, type, protocol)) < 0)
  25. #else
  26. if ((sockfd = socket(domain, type, protocol)) == INVALID_SOCKET)
  27. #endif
  28. {
  29. fprintf(stderr, "op_socket error/n");
  30. exit(EXIT_FAILURE);
  31. }
  32. return sockfd;
  33. }
  34. // 接收客户端的socket请求
  35. int op_accept(OP_SOCKET sockfd, OP_SOCKADDR *addr, OP_SOCKLEN_T *addrlen)
  36. {
  37. int ret;
  38. if ((ret = accept(sockfd, addr, addrlen)) < 0)
  39. {
  40. fprintf(stderr, "op_accept error/n");
  41. exit(EXIT_FAILURE);
  42. }
  43. return ret;
  44. }
  45. // IP的点分十记转化为IP的结构体
  46. unsigned long op_inet_addr(const char *dst)
  47. {
  48. long ret;
  49. if ((ret = inet_addr(dst)) < 0)
  50. {
  51. fprintf(stderr, "op_inet_addr error for %s/n", dst);
  52. exit(EXIT_FAILURE);
  53. }
  54. return (unsigned long)ret;
  55. }
  56. // sockfd指定的套接字连接到addr指定的服务器套接字
  57. int op_connect(OP_SOCKET sockfd, const OP_SOCKADDR *addr, OP_SOCKLEN_T addrlen)
  58. {
  59. int ret;
  60. if ((ret = connect(sockfd, addr, addrlen)) < 0)
  61. {
  62. fprintf(stderr, "op_connect error/n");
  63. exit(EXIT_FAILURE);
  64. }
  65. return ret;
  66. }
  67. // addr指定的地址分配给与文件描述符socket关联的未命名套接字
  68. int op_bind(OP_SOCKET sockfd, const OP_SOCKADDR *addr, OP_SOCKLEN_T addrlen)
  69. {
  70. int ret;
  71. if ((ret = bind(sockfd, addr, addrlen)) < 0)
  72. {
  73. fprintf(stderr, "op_bind error/n");
  74. exit(EXIT_FAILURE);
  75. }
  76. return ret;
  77. }
  78. // 监听client请求,backlog指定最大连接数
  79. int op_listen(OP_SOCKET sockfd, int backlog)
  80. {
  81. int ret;
  82. if ((ret = listen(sockfd, backlog)) < 0)
  83. {
  84. fprintf(stderr, "op_listen error/n");
  85. exit(EXIT_FAILURE);
  86. }
  87. return ret;
  88. }
  89. // send发送消息
  90. int op_send(OP_SOCKET sockfd, const char *buffer, size_t len, int flags)
  91. {
  92. int ret;
  93. if ((ret = send(sockfd, buffer, len, flags)) < 0)
  94. {
  95. fprintf(stderr, "op_send error/n");
  96. exit(EXIT_FAILURE);
  97. }
  98. return ret;
  99. }
  100. // recv接收消息
  101. int op_recv(OP_SOCKET sockfd, char *buffer, size_t len, int flags)
  102. {
  103. size_t ret;
  104. op_clean_buffer(buffer, len);
  105. if ((ret = recv(sockfd, buffer, len, flags)) < 0)
  106. {
  107. fprintf(stderr, "op_recv error/n");
  108. exit(EXIT_FAILURE);
  109. }
  110. return ret;
  111. }
  112. // 关闭socket或文件指针
  113. int op_close(OP_SOCKET sockfd)
  114. {
  115. int ret;
  116. #ifndef WIN32
  117. if ((ret = close(sockfd)) < 0)
  118. #else
  119. if((ret = closesocket(sockfd)) < 0)
  120. #endif
  121. {
  122. fprintf(stderr, "op_close error/n");
  123. exit(EXIT_FAILURE);
  124. }
  125. return ret;
  126. }
  127. // 打开文件
  128. FILE* op_fopen(const char *path, const char *mode)
  129. {
  130. FILE *fp = fopen(path, mode);
  131. if (NULL == fp)
  132. {
  133. printf("File:/t%s Can Not Open To Write/n", path);
  134. exit(EXIT_FAILURE);
  135. }
  136. return fp;
  137. }
  138. // 关闭文件指针
  139. int op_fclose(FILE *stream)
  140. {
  141. int ret;
  142. if ((ret = fclose(stream)) < 0)
  143. {
  144. fprintf(stderr, "op_fclose error/n");
  145. exit(EXIT_FAILURE);
  146. }
  147. return ret;
  148. }
  149. // 休眠函数,对于usleep为微秒级别,对于Sleep为毫秒级别
  150. void op_sleep(int micro_seconds)
  151. {
  152. #ifndef WIN32
  153. usleep(micro_seconds);
  154. #else
  155. Sleep(micro_seconds);
  156. #endif
  157. }
  158. // 字符串比较函数
  159. int op_stricmp(char *s1,char * s2)
  160. {
  161. #ifndef WIN32
  162. return strcasecmp(s1, s2);
  163. #else
  164. return stricmp(s1, s2);
  165. #endif
  166. }

六、完成了上述的操作之后,就可以分别对client和server端进行编译了,先启动server端服务器,然后用命令行的形式运行client端,就可以成功了吧。哈哈!我们来看一下使用protobuf进行socket通信的实际效果!给大家截个图!

时间: 2025-01-16 14:35:49

VS下使用Google Protobuf完成SOCKET通信的相关文章

基于google protobuf 的 socket udp 通信

SocketClient.cpp #include "SocketClient.h" #include "ClientInfoSave.h" #include "serverMsg.pb.h" using namespace Message; string SocketClient::m_strHeatMsg = ""; set<BaseView*> SocketClient::m_set_BaseView; in

linux下安装google protobuf(详细)

说明: protobuf已经全面迁移到github,地址:https://github.com/google/protobuf 直接下载2.6.1版本:https://github.com/google/protobuf/archive/v2.6.1.zip 我转linux不久所以对linux的各种系统路径不是特别熟悉,网上看了几个教程都没有提到 添加 LIBRARY_PATH路径,导致自定义安装路径的时候链接不过(尤其是非root用户默认安装的路径是没有权限的,需要修改安装安装路径),所以自己

通信框架浅析--google protobuf vs facebook thirft

protobuf 请参考下面这篇文章 http://blog.csdn.net/hguisu/article/details/20721109 WINDOWS配置THRIFT开发环境 1)安装thrift:到thrift官网下载exe文件,然后将文件重命名为thrift.exe,拷贝到c:\windows目录下(或者任何目录下),然后就可以在dos环境下使用了 c:\windows>thrift -gen java D:\mywork\javaProject\thriftTest\test.th

google protobuf学习笔记一:windows下环境配置

欢迎转载,转载请注明原文地址:http://blog.csdn.net/majianfei1023/article/details/45371743 protobuf的使用和原理,请查看:http://blog.csdn.net/majianfei1023/article/details/45112415 Windows下google protobuf开发环境配置 最近项目需求,Client与Server的网络通信协议传输使用google protobuf rpc.对于Protobuf,以前是只

(8)Linux(客户端)和Windows(服务端)下socket通信实例

Linux(客户端)和Windows(服务端)下socket通信实例: (1)首先是Windows做客户端,Linux做服务端的程序 Windows   Client端 #include <stdio.h> #include <Windows.h> #pragma comment(lib, "ws2_32.lib") #define Port 5000 #define IP_ADDRESS "192.168.1.30"     //服务器地址

Linux下简单的socket通信实例

Linux下简单的socket通信实例 If you spend too much time thinking about a thing, you’ll never get it done. —Bruce Lee       学习网络编程也一段时间了,刚开始看<UNIX网络编程>的时候,觉得这本厚厚的书好难啊!看到后来,发现并没有想象中的那么难.如果你是新手,建议你看到第二部分结束后,开始着手写代码.不写代码肯定是不行的.看100遍也没有敲一遍实现一遍来的清楚.敲完以后,带着问题去看书,你会

Windows环境下google protobuf入门

我使用的是最新版本的protobuf(protobuf-2.6.1),编程工具使用VS2010.简单介绍下google protobuf: google protobuf 主要用于通讯,是google出的一个结构化信息传递工具,有着效率高.占存储少的优点,常被用于网络通讯. Google protobuf主要是针对Linux下的开发,但是为了照顾windows的开发人员,google也给出了相应的方案. windows下,需要下载两个包protobuf-2.6.1.tar.bz2和protobu

Linux下进程间Socket通信调试debug方法

在一个复杂的软件系统中,往往需要有各个组件之间的数据传递,在组件间数据传递过程中,又会不可避免的出现一些小问题,这时候我们就需要来进行debug了,由于最近的一个系统使用到了collectd和rrdcached来收集数据和画图,它们之间采用了Unix socket通信,因此小小的学习了一下相关知识. 首先我们来回忆下Linux下进程通信有哪些方法: 管道(Pipe)及有名管道(FIFO)\UNIX BSD 信号(Signal) \UNIX BSD 报文消息队列(Message)\UNIX sys

windows下QT前台和linux下后台程序通过socket通信

通常情况下,linux下的后台程序不需要GUI进行展示,而前台程序往往有个界面,方便和用户的交互.本文所演示的例 子,是QT 程序和后台linux进程(C语言)交互,通过socket传输的内容是结构体.因为QT本身是跨平台的框架,因此以后前端程序移植到其它平台依然能很好 的运行. 结构体的定义如下: struct Test              {                      int a;                      char b;              };