一种比较搓的方式利用Google Protoco来进行客户端服务器数据通信
A客户端模块:
1.新建一个win32控制台应用程序,是空项目,名字为MyCient
2. Google Protocol环境配置(详细配置看我文章http://blog.csdn.net/dugaoda/article/details/50342449)
2.1.
2.2.添加lib文件到项目Debug下面
3.生成协议person. proto
内容为
package tutorial;
message Person { required string name = 1; required int32 age = 2; optional string email = 3;
}
message msg { required int32 id = 1; // message ID required int32 len = 2; //message Length required bytes info = 3; //message content = 二进制方式. } |
得到person.pb.h和person.pb.cc
4.新建文件MyClient.cpp
同时添加文件person.pb.h和person.pb.cc
项目文件结构如下
5.编写MyClient.cpp文件内容
先直接贴上代码
// MyClient.cpp : 定义控制台应用程序的入口点。 //
#include "winsock2.h" #include <iostream> #include <fstream> #include "person.pb.h" #include "TCPPakDef.hpp" #pragma comment(lib, "ws2_32.lib")
using namespace std; using namespace tutorial;
BOOL RecvLine(SOCKET s, char *buf);
int main() { tutorial::Person PERSON;
const int BUF_SIZE = 1024; WSADATA wsd; SOCKET sHost; SOCKADDR_IN servAddr; char buf[BUF_SIZE]="";//接收数据缓冲区 char bufRecv[BUF_SIZE]=""; //截断后面的乱码输出 cout << endl << "1从服务器接受数据:" << buf; cout << endl << "2从服务器接受数据:" << bufRecv; int retVal;
//初始化套结字动态库 if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0) { cout << "WSAStartup failded!" << endl; return 1; }
//创建套接字 sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == sHost) { WSACleanup();//释放套接字资源 return -1; }
//设置服务器地址 servAddr.sin_family = AF_INET; servAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); servAddr.sin_port = htons((short)123); int nServAddlen = sizeof(servAddr);
//连接服务器 retVal = connect(sHost, (LPSOCKADDR)&servAddr, sizeof(servAddr)); if (SOCKET_ERROR == retVal) { cout << "connect failed" <<endl; closesocket(sHost); WSACleanup(); return -1; }
while (true) { //向服务器发送数据 ZeroMemory(buf, BUF_SIZE); cout << "向服务器发送数据:"; char buf123[BUF_SIZE]=""; cin >> buf123;
//使用google protobuf 将数据发送出去 //其实在每个MSG的头上面加上ID 在服务器上面解析出来就可以用了 PERSON.set_name("dugoada"); PERSON.set_age(123); string data; PERSON.SerializeToString(&data); char dst[BUF_SIZE]; strcpy(dst, data.c_str()); retVal = send(sHost, dst, sizeof(dst), 0);
if (SOCKET_ERROR == retVal) { cout << "send failed!" << endl; closesocket(sHost);//关闭套接字 WSACleanup(); return -1; }
// 接收服务器端的数据 ZeroMemory(buf, BUF_SIZE); recv(sHost, bufRecv, BUF_SIZE, 0); cout << endl << "从服务器接受数据:" << bufRecv; }
closesocket(sHost);//关闭套接字 WSACleanup();
return 0; } |
6.关键代码说明
//使用google protobuf 将数据发送出去 //其实在每个MSG的头上面加上ID 在服务器上面解析出来就可以用了 PERSON.set_name("dugoada"); PERSON.set_age(123); //将PERSON的数据内容序列化到data中 string data; PERSON.SerializeToString(&data);
//将data数据copy到dst中 发送的时候需要用到的是char类型的字符 char dst[BUF_SIZE]; strcpy(dst, data.c_str()); |
B 服务器模块:
环境配置部分跟客户端一样,代码不一样(注意)
1.编写MyServer.cpp文件内容
先直接贴上代码
// MyServer.cpp : 定义控制台应用程序的入口点。 //
//#include "stdafx.h" #include "winsock2.h" #pragma comment(lib, "ws2_32.lib") #include <iostream> using namespace std;
#include <iostream> #include<fstream> #include "TCPPakDef.hpp" #include "person.pb.h"
using namespace tutorial;
int main() {
tutorial::Person PERSON;
const int BUF_SIZE = 1024; WSADATA wsd; SOCKET sServer; SOCKET sClient; SOCKADDR_IN addrServ; char buf[BUF_SIZE]; char sendBuf[BUF_SIZE]; int retVal;
//初始化套结字动态库 if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0) { cout << "WSAStartup failded!" << endl; return 1; }
//创建套接字 sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (INVALID_SOCKET == sServer) { cout << "socket failed!" << endl; WSACleanup(); return -1; }
//服务器套接字地址信息设置 addrServ.sin_family = AF_INET; addrServ.sin_port = htons(123); addrServ.sin_addr.s_addr = INADDR_ANY;
//绑定 retVal = bind(sServer, (LPSOCKADDR)&addrServ, sizeof(SOCKADDR_IN)); if (SOCKET_ERROR == retVal) { cout << "bind failed!" << endl; closesocket(sServer); WSACleanup(); return -1; }
//开始监听 retVal = listen(sServer, 1); if (SOCKET_ERROR == retVal) { cout << "listen failed!" << endl; closesocket(sServer); WSACleanup(); return -1; }
//接受客户端请求 sockaddr_in addrClient; int addrClientlen = sizeof(addrClient); sClient = accept(sServer, (sockaddr FAR *)&addrClient, &addrClientlen);
if (INVALID_SOCKET == sClient) { cout << "accept failed!" << endl; closesocket(sServer); WSACleanup(); return -1; }
//数据处理 while (true) { //接受客户端数据 ZeroMemory(buf, BUF_SIZE); retVal = recv(sClient, buf, BUF_SIZE, 0);
//方法1 解析google protobuf string data = buf; PERSON.ParseFromString(data); cout << "Name: " << PERSON.name() << endl; cout << "Age: " << PERSON.age() << endl;
if (SOCKET_ERROR == retVal) { cout << "recv, failed!" << endl; closesocket(sClient); closesocket(sServer); WSACleanup(); return -1; }
if (buf[0] == '0') break;
cout << "客户端发送的数据:" << buf << endl; cout << "向客户端发送数据:"; cin >> sendBuf; send(sClient, sendBuf, strlen(sendBuf), 0);
}
closesocket(sClient); closesocket(sServer); WSACleanup();
return 0; } |
6.关键代码说明
//方法1 解析google protobuf //将数据从data解析到PERSON中 string data = buf; PERSON.ParseFromString(data); //得到自己想要的数据 cout << "Name: " << PERSON.name() << endl; cout << "Age: " << PERSON.age() << endl;
|