Socket编程+Google Protocol搭建简单的客户端服务器方式1

来源:互联网 发布:mac os x 原版dmg 编辑:程序博客网 时间:2024/06/07 20:11

一种比较搓的方式利用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; 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0 0
原创粉丝点击