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

来源:互联网 发布:易语言股票助理源码 编辑:程序博客网 时间:2024/06/14 11:16

客户端模块:

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.新建TCPPakDef.hpp

TCPPakDef.hpp内容。buf的前8个字节的内容,包头的内容封装。

 

 

 

#ifndef __OMP_TCPPAKDEF_HEADER_FILE__

#define __OMP_TCPPAKDEF_HEADER_FILE__

 

//#include "OmpConfig.hpp"

 

//#include <boost/static_assert.hpp>

#include <cstdlib>

 

namespace omp {

         namespace net {

 

 

                   //      TCP Packet Define

                   //

 

#pragma pack(push,1)

 

                   struct tcp_pak_header

                   {

                            char flag[4];

                            int              length;

 

                            inline void reset()

                            {

                                     //flag[0] = 'f';

                                     //flag[1] = 'l';

                                     //flag[2] = 'a';

                                     //flag[3] = 'g';

 

                                     // WARNING:

                                     //

                                     //               only for little-endian processor now !!!

                                     //

                                     *((int*)flag) = 0x67616c66;

                                     length = 0;

                            }

 

                            bool check()

                            {

#ifdef _DEBUG

                                     char str[5];

 

                                     memset( str,'\0',sizeof(str) );

                                     memcpy( str,&length,4 );

 

                                     if( str[0] == '0' && ( str[1] == 'x' || str[1] == 'X' ) )

                                     {

                                               char *ptr_stop(0);

                                               length = std::strtoul( str,&ptr_stop,16 );

                                               if( ptr_stop != &str[4] )

                                                        return false;

                                     }

 

#endif//#ifdef _DEBUG

 

                                     // WARNING:

                                     //

                                     //               only for little-endian processor now !!!

                                     //

                                     return( *((int*)flag) == 0x67616c66 && length );

                            }

                   };

 

#pragma pack(pop)

 

//               BOOST_STATIC_ASSERT( sizeof(char)==1 );

//               BOOST_STATIC_ASSERT( sizeof(int)==4 );

//               BOOST_STATIC_ASSERT( sizeof(tcp_pak_header)==8 );

 

         }        // end of namespace net

 

}        // end of namespace omp

 

#endif//#define __OMP_TCPPAKDEF_HEADER_FILE__

 

5.新建文件MyClient.cpp

同时添加文件person.pb.h和person.pb.cc和TCPPakDef.hpp

项目文件结构如下

 

 

6.编写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);

 

 

                   ////*方式2 发送数据 加上包的编号*//

                   //新的

                   google::protobuf::Message* user_send_msg;

                   PERSON.set_name("dugoada");

                   PERSON.set_age(123);

                   user_send_msg = &PERSON;

 

                   tutorial::msg head;// 包的ID  包的长度为Msg的ByteSize

                   head.set_id(1);

                   int nLength = 0;

                   if ( user_send_msg ) nLength = user_send_msg->ByteSize();

                   head.set_len(nLength);

 

                   if (nLength > 0)

                   {

                            //序列化之后的字符串 将数据存入到 head.info();

                            user_send_msg->SerializeToString(head.mutable_info());

                   }

                   //将数据组装到head完毕

 

                   //设置tcp的内容

                   omp::net::tcp_pak_header tcp = {0};

                   int tcplength = sizeof(tcp);//tcplength = 8;

                   int nLen = head.ByteSize() + sizeof(tcp);//包头的长度+message的size

                   tcp.length = htonl(nLen);

                   //设置 tcp.length的值

 

                   //将tcp首地址开始 到sizeof(tcp)的长度  将数据存入到Buf中  处理Buff前8个长度

                   ::memcpy(buf, &tcp, sizeof(tcp));

 

                   //进行序列化,将head中的数据全部序列化到buf+sizeof(tcp)中   处理Buff从8开始到最后

                   head.SerializeToArray(buf+sizeof(tcp), nLen);

 

                   retVal = send(sHost, buf, nLen, 0);

                   ////buf  nLen

                   ////*发送数据 加上包的编号*//

 

                   //retVal = send(sHost, buf, strlen(buf), 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;

}

 

 

7.关键代码说明

////*方式2 发送数据 加上包的编号*//

                   //新的

                   google::protobuf::Message* user_send_msg;

                   PERSON.set_name("dugoada");

                   PERSON.set_age(123);

                   user_send_msg = &PERSON;

 

                   tutorial::msg head;// 包的ID  包的长度为Msg的ByteSize

                   head.set_id(1);

                   int nLength = 0;

                   if ( user_send_msg ) nLength = user_send_msg->ByteSize();

                   head.set_len(nLength);

 

                   if (nLength > 0)

                   {

                            //序列化之后的字符串 将数据存入到 head.info();

                            user_send_msg->SerializeToString(head.mutable_info());

                   }

                   //将数据组装到head完毕

 

                   //设置tcp的内容

                   omp::net::tcp_pak_header tcp = {0};

                   int tcplength = sizeof(tcp);//tcplength = 8;

                   int nLen = head.ByteSize() + sizeof(tcp);//包头的长度+message的size

                   tcp.length = htonl(nLen);

                   //设置 tcp.length的值

 

                   //将tcp首地址开始 到sizeof(tcp)的长度  将数据存入到Buf中  处理Buff前8个长度

                   ::memcpy(buf, &tcp, sizeof(tcp));

 

                   //进行序列化,将head中的数据全部序列化到buf+sizeof(tcp)中   处理Buff从8开始到最后

                   head.SerializeToArray(buf+sizeof(tcp), nLen);

 

                   retVal = send(sHost, buf, nLen, 0);

                   ////buf  nLen

                   ////*发送数据 加上包的编号*//

 

 

 

 

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; 

                   int nHeadLength = sizeof(omp::net::tcp_pak_header);

                   //char receveBuf[BUF_SIZE];

                   omp::net::tcp_pak_header* pTcpMsg = (omp::net::tcp_pak_header*)buf;

                   unsigned short wAllSize = ntohl(pTcpMsg->length);

                   int nPacketSize = wAllSize - nHeadLength;//得到  tutorial::msg 的ByteSize()

 

                   tutorial::msg head;

                   head.ParseFromArray(buf+nHeadLength, nPacketSize);

 

                   unsigned char cbDataBuffer[1024+20];

 

                   //将head的数据放入到buf中

                   ::memcpy(cbDataBuffer, head.info().data(), head.info().length());

 

                   //::memmove(buf, buf+nPacketSize, m_wRecvSize);

 

                   int sfde = head.id();

                   cbDataBuffer;

                   nPacketSize;

 

                   tutorial::Person PP;

                   PP.ParseFromArray(cbDataBuffer, nPacketSize);

                   string sfe = PP.name();

                   int asfewe = PP.age();

                   cout << "名字:" << PP.name() << endl;

                   cout << "年龄:" << PP.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.关键代码说明

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; 

                   int nHeadLength = sizeof(omp::net::tcp_pak_header);

                   //char receveBuf[BUF_SIZE];

                   omp::net::tcp_pak_header* pTcpMsg = (omp::net::tcp_pak_header*)buf;

                   unsigned short wAllSize = ntohl(pTcpMsg->length);

                   int nPacketSize = wAllSize - nHeadLength;//得到  tutorial::msg 的ByteSize()

 

                   tutorial::msg head;

                   head.ParseFromArray(buf+nHeadLength, nPacketSize);

 

                   unsigned char cbDataBuffer[1024+20];

 

                   //将head的数据放入到buf中

                   ::memcpy(cbDataBuffer, head.info().data(), head.info().length());

 

                   //::memmove(buf, buf+nPacketSize, m_wRecvSize);

 

                   int sfde = head.id();

                   cbDataBuffer;

                   nPacketSize;

 

                   tutorial::Person PP;

                   PP.ParseFromArray(cbDataBuffer, nPacketSize);

                   string sfe = PP.name();

                   int asfewe = PP.age();

                   cout << "名字:" << PP.name() << endl;

                   cout << "年龄:" << PP.age() << endl;

 

 

 

 

 

0 0
原创粉丝点击