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;
- Socket编程+Google Protocol搭建简单的客户端服务器方式2
- Socket编程+Google Protocol搭建简单的客户端服务器方式1
- 简单socket编程,服务器、客户端
- socket编程:简单TCP服务器/客户端编程
- socket编程:简单UDP服务器/客户端编程
- Linux socket编程-最简单的服务器和客户端程序
- Windows Socket 编程_ 简单的服务器/客户端程序
- socket编程:服务器与客户端简单交互的例子
- Linux socket编程-最简单的服务器和客户端程序
- Windows Socket 编程_ 简单的服务器/客户端程序 .
- Windows Socket 编程_ 简单的服务器/客户端程序
- linux socket 编程一:简单的服务器和客户端通信
- Windows Socket 编程_ 简单的服务器/客户端程序
- Windows Socket 编程_ 简单的服务器/客户端程序
- Windows Socket 编程_ 简单的服务器/客户端程序
- Windows Socket 编程_ 简单的服务器/客户端程序
- Windows Socket 编程_ 简单的服务器/客户端程序 .
- Windows Socket 编程_ 简单的服务器/客户端程序
- 奇葩的Android Bug: Unable to start service Intent
- float和Float的问题,错误原因:cannot be translated into a null value
- iOS "dyld`dyld_fatal_error: -> 0x12000d088 <+0>: brk #0x3"错误
- 安卓应用的版本更新
- [LeetCode]150. Evaluate Reverse Polish Notation
- Socket编程+Google Protocol搭建简单的客户端服务器方式2
- C语言实现双向非循环链表(带头结点尾结点)的节点插入
- 两物体相对位置、追踪速度方向、朝向等计算方向以及角度
- 金牛VS天蝎
- collectionviewcell的圆角和阴影问题
- 【笔记】《C#大学教程》- 第5章 控制结构(二)
- sql查询 ,多行数据合并成一行,并且显示合并后某一列的值拼接结果
- 1008: 数列
- 大话设计模式-原型模式