传递的消息是简单的char*的话,客户端和服务器端以及protoc文件分别如下:
//.protoc文件,包含的信息是身份证号,姓名和生日
package tutorial;
message Person
{
required string id = 1;
required string name = 2;
required int32 birthyear=3;
required int32 birthmonth=4;
required int32 birthday=5;
}
//客户端
#pragma warning(disable : 4996)
#include<iostream>
#include "protobuf_test.pb.h"
#include "socket/wsock.h"
//#include<winsock.h>
#include <io.h>
#include <fstream>
#include "Base64.h"
#pragma comment(lib,"ws2_32.lib")
#pragma comment(lib,"libprotobuf.lib")
#pragma comment(lib,"libprotoc.lib")
using namespace std;
using namespace tutorial;
void initialization();
int setPerson();
string getImg();
//定义长度变量
int send_len = 0;
int recv_len = 0;
//定义发送缓冲区和接受缓冲区
char send_buf[1024 * 1024 * 5];
char recv_buf[100];
char ImgBuff2[10000000];
int main()
{
//定义服务端套接字,接受请求套接字
SOCKET soc_server;
//服务端地址客户端地址
SOCKADDR_IN server_addr;
cout << "---------client---------" << endl << endl;
//初始化套接字库
initialization();
//填充服务端信息
server_addr.sin_family = AF_INET;//代表TCP/IP协议族
server_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//IP地址,sin_addr存储IP地址,使用in_addr这个数据结构
server_addr.sin_port = htons(5010);//端口号
// htons函数:将一个16位无符号短整型数据由主机排列方式转化为网络排列方式,htonl函数的作用恰好相反。
//创建套接字
/*
SOCKET socket(int af,int type,int protocol);
af:一个地址家族,通常为AF_INET
type:套接字类型,SOCK_STREAM表示创建面向流连接的套接字。为SOCK_DGRAM,表示创建面向无连接的数据包套接字。为SOCK_RAW,表示创建原始套接字
protocol:套接字所用协议,不指定可以设置为0
返回值:socket
*/
soc_server = socket(AF_INET, SOCK_STREAM, 0);
//向服务器发出连接请求
/*
connect函数:客户端socket发送连接请求的函数,
第一个参数是客户端的socket,
第二个参数是一个结构体指针,里面包括连接主机的地址和ip,
第三个参数为缓冲区的长度。
成功返回0,出错返回-1
*/
while (connect(soc_server, (SOCKADDR *)&server_addr, sizeof(SOCKADDR)) == -1)
{
cout << "服务器连接失败!" << endl;
//WSACleanup();
Sleep(2000);
}
// else
// {
// cout << "服务器连接成功!" << endl;
// }
//发送数据
while (1)
{
int len = setPerson();
if (len < 0){
return -1;
}
send_len = send(soc_server, send_buf, len, 0);
if (send_len < 0)
{
cout << "发送失败!" << endl;
break;
}
printf("send %d bytes.\n", send_len);
recv_len = recv(soc_server, recv_buf, 100, 0);
if (recv_len < 0)
{
cout << "接受失败!" << endl;
break;
}
else
{
cout << "服务端信息:" << recv_buf << endl;
}
}
//关闭套接字
closesocket(soc_server);
//释放DLL资源
WSACleanup();
return 0;
}
//初始化套接字库
void initialization()
{
WORD w_req = MAKEWORD(2, 2);//版本号
WSADATA wsadata;
//检查初始化套接字库
if (WSAStartup(w_req, &wsadata) != 0)
{
cout << "初始化套接字库失败!" << endl;
}
// else
// {
// cout << "初始化套接字库成功!" << endl;
// }
//检测版本号
if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2)
{
cout << "套接字库版本号不符!" << endl;
WSACleanup();
}
// else
// {
// cout << "套接字库版本正确!" << endl;
// }
}
//protobuf序列化信息
int setPerson(){
Person p;
// cout << "输入身份证号:";
// char id[220];
// cin >> id;
// p.set_id(id);
// cin.ignore(256, '\n');
// cout << "输入姓名:";
// string name;
// getline(cin, *p.mutable_name());
// cin.ignore(256, '\n');
// cout << "输入出生日期:";
// cout << endl << "年:";
// int year;
// cin >> year;
// p.set_birthyear(year);
// cin.ignore(256, '\n');
// cout << endl << "月:";
// int month;
// cin >> month;
// p.set_birthmonth(month);
// cin.ignore(256, '\n');
//
// cout << endl << "日:";
// int day;
// cin >> day;
// p.set_birthday(day);
// cin.ignore(256, '\n');
p.set_id("510122199611147760");
p.set_name("gugu");
p.set_birthyear(1996);
p.set_birthmonth(11);
p.set_birthday(14);
p.set_imgname("sichuanuniversity");
string data = getImg();
p.set_imgdata(data);
int proto_len = p.ByteSize();/*
if (proto_len >= sizeof(send_buf))
exit(0);*/
assert(proto_len < sizeof(send_buf));
bool bret = p.SerializeToArray(send_buf, proto_len);
//assert(bret);
if (!bret){
fprintf(stderr, "SerializeToArray failed\n");
return -1;
}
return proto_len;
}
//从本地获取图片 加密图片
string getImg()
{
string ImgName = "sichuanuniversity.jpg";
ifstream StreamImg;
StreamImg.open(ImgName.c_str(), ios_base::in | ios_base::out | ios_base::binary);//第一个参数是打开文件名字,第二个是打开的模式:ios_base::binary是二进制模式,ios_base::in是以读的方式打开
StreamImg.seekg(0, ios::end);//seekg作用是输入指针移到指定的文件位置,第一个参数是需要偏移的值(正数向后偏移),第二个参数是搜索的位置(ios::end输入流结束位置,ios::beg开始位置,ios::cur当前位置)
int ImgSize = StreamImg.tellg();//tellg()不需要带参数,它返回当前定位指针的位置,也代表着输入流的大小
printf("img size: %d\n", ImgSize);
char* ImgBuff = new char[ImgSize + 1];//图片的缓存区
string _base64;
Base64 encrypt;//加密
StreamImg.seekg(0, ios::beg);//输入指针指向开始位置
StreamImg.read(ImgBuff, ImgSize);//ImgSize个字符到ImgBuff这个缓冲区
_base64 = encrypt.Encode((unsigned char*)ImgBuff, ImgSize + 1);//加密
int eLen = _base64.length();//加密之后的长度
memcpy_s(ImgBuff2, sizeof(ImgBuff2), _base64.c_str(), eLen);//四个参数(目的地址,目的地址字符个数(sizeof获取),源地址,需要拷贝的原字符个数) 是一个内存复制函数
StreamImg.close();
delete ImgBuff;
return ImgBuff2;//返回加密之后的内存地址
}
//服务器端
#pragma warning(disable : 4996)
#include<iostream>
#include<winsock.h>
#include "base64.h"
#include "protobuf_test.pb.h"
#include <fstream>
#include <stdlib.h>
#include <stdio.h>
#include<cstdlib>
#include <io.h>
#include<typeinfo>
#pragma comment(lib,"libprotobuf.lib")
#pragma comment(lib,"libprotoc.lib")
#pragma comment(lib,"ws2_32.lib")
using namespace std;
using namespace tutorial;
void initialization();
//定义长度变量
int send_len = 0;
int recv_len = 0;
int len = 0;
//定义发送缓冲区和接受缓冲区
char send_buf[100];
char recv_buf[1024 * 1024];
int main() {
//定义服务端套接字,接受请求套接字
SOCKET soc_server;
SOCKET soc_accept;
//服务端地址客户端地址
SOCKADDR_IN server_addr;
SOCKADDR_IN accept_addr;
cout << "-----------server-----------------" << endl << endl;
//初始化套接字库
initialization();
//填充服务端信息
server_addr.sin_family = AF_INET;//ipv4
server_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//绑定默认的网卡
server_addr.sin_port = htons(5010);//和客户端使用相同的端号5010
//创建套接字
soc_server = socket(AF_INET, SOCK_STREAM, 0);
//绑定套接字在一个IP地址个一个端口上
if (bind(soc_server, (SOCKADDR *)&server_addr, sizeof(SOCKADDR)) == -1)
{
cout << "套接字绑定失败!" << endl;
WSACleanup();
}
// else
// {
// cout << "套接字绑定成功!" << endl;
// }
//设置套接字为监听状态
if (listen(soc_server, SOMAXCONN) < 0)
{
cout << "设置监听状态失败:" << WSAGetLastError() << endl;
WSACleanup();
}
// else
// {
// cout << "设置监听状态成功!" << endl;
// }
cout << "服务端正在监听连接,请稍候...." << endl;
//接受连接请求
len = sizeof(SOCKADDR);
soc_accept = accept(soc_server, (SOCKADDR *)&accept_addr, &len);
if (soc_accept == -1) {
cout << "连接失败:" << WSAGetLastError() << endl;
WSACleanup();
return 0;
}
cout << "连接建立,准备接受数据" << endl;
//接收数据
while (1) {
int len = recv(soc_accept, recv_buf, sizeof(recv_buf), 0);
if (len < 0)
{
cout << "接受失败!" << endl;
break;
}
//反序列化
Person p;
p.ParseFromArray(recv_buf, len);
//打印基本信息
cout << "身份证号:" << p.id() << endl;
cout << "名字:" << p.name() << endl;
cout << "出生日期:" << p.birthyear() << "." << p.birthmonth() <<"." << p.birthday() << endl;
//图片解密
string _base64;
Base64 decrypt;
memset(recv_buf,0,sizeof(recv_buf));//memset方便清空一个结构体或者数组,第一个参数是指针或者数组,第二个参数是给数组的值(一般为0,相当于初始化),第三个参数是数组的长度(由sizeof来求)
int OutByte = 0;
string imgStr = p.imgdata();
string ImgBuff = decrypt.Decode(p.imgdata().c_str(), strlen(p.imgdata().c_str()), OutByte);
//char img[1000000];
//memcpy_s(img, sizeof(img), ImgBuff.c_str(), OutByte);
printf("image file len: %d\n", OutByte);
FILE*fp;
fp = fopen("sichuanuniversity.jpg", "wb");
fwrite(ImgBuff.c_str(), 1, OutByte, fp);
cout << "图片接收成功,存入当前项目路径!" << endl;
fclose(fp);
///
//显示图片
cout << "图片:" <<p.imgname()<< endl;
system("sichuanuniversity.jpg");
cout << "请输入回复信息:";
cin >> send_buf;
cout << endl;
send_len = send(soc_accept, send_buf, 100, 0);
if (send_len < 0)
{
cout << "发送失败!" << endl;
break;
}
}
//关闭套接字
closesocket(soc_server);
closesocket(soc_accept);
//释放DLL资源
WSACleanup();
system("pause");
return 0;
}
//初始化套接字库
void initialization() {
//初始化
WSADATA wsadata;
if (WSAStartup(MAKEWORD(2, 2), &wsadata))
{
cout << "初始化套接字失败!" << endl;
return;
}
// else
// {
// cout << "初始化套接字成功!" << endl;
// }
//检测版本号
if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2)
{
cout << "套接字库版本号不符!" << endl;
WSACleanup();
return;
}
// else
// {
// cout << "套接字库版本正确!" << endl;
// }
}