UDP通讯之字节流与protobuf转换(C++版)
-
- 说明
- 工程内容
-
- VS2017工程介绍
- VS2017工程基本设置
- 数据结构体
- UDP服务端server与客户端client类的封装
- 初始化IP与Port的配置文件(ini格式)的封装
- 大小端转换类的封装
- 主函数的介绍与使用
- 另一台电脑调用
说明
- 只做了车辆信息与控制信息两部分,简易流程图如下
- 工程在VS2017下用C++编写完成,已经做过初步测试,可以通讯使用
- 所有通讯内容是proto2版本,亲测装的proto3版本可以兼容使用
- 有一个大小端转换问题,阳哥控制接收端与我这边UDP发送大小端相反,做了一下转换

工程内容
- VS2017基本设置与工程介绍
- UDP服务端server与客户端client类的封装
- 初始化IP与Port的配置文件(ini格式)的封装
- 大小端转换类的封装
- 主函数的介绍与使用
VS2017工程介绍
- 解决方案名称TestOfProtobuf下包含两个项目工程,第一个SimulatorDataExchange为最终完成的项目,第二个为第一版测试,可以忽略。
- SimulatorDataExchange工程项目下头文件构成。

- imulatorDataExchange工程项目下源文件构成。

- 资源文件要将所有用到的proto文件加载进来。

VS2017工程基本设置
- 注意工程是Debug还是Release,64位还是32位,这个要跟protobuf编译时要一致,我使用的是Debug64位。
- 右键点击项目,打开属性

- C/C++中附加包含目录:包含你的protobuf版本的google头文件。
- 下面的SDL检查设为否(/sdl-)

- C/C++中代码生成运行库为多线程调试(/MTd)

- 链接器下附加库目录:将你protobuf编译出来的三个lib文件目录指定

- 链接器下输入->附加依赖项:将三个lib名字加进去。

数据结构体
#pragma once
struct CarMsg
{
long long utime;
int nauto;
float steerPos;
int steerSpe;
int light;
float speLeft;
float speRight;
float vot;
int shift;
float disLeft;
float disRight;
float speo;
float yawRate;
float accelerationLon;
float accelerationLat;
};
struct GPSMsg
{
long long utime;
double longitude;
double latitude;
float altitude;
float yaw;
float roll;
float pitch;
float yawRate;
float velocityNorth;
float velocityEast;
float velocityDown;
float accelerationLongitudinal;
float accelerationLateral;
float acceleration;
float velocity;
float locationStatus;
float confidenceLevel;
float yawEstimate;
double longitudeEstimate;
double latitudeEstimate;
short satelliteNumber;
};
struct ControlMsg
{
long long utime;
double throttle;
double brake;
double steeringRate;
double steeringTarget;
double speed;
double acceleration;
bool engineOnOff;
bool leftTurn;
bool rightTurn;
bool horn;
bool parkingBrake;
bool resetModel;
short drivingMode;
short gearLocation;
};
struct TrafficLightMsg
{
long utime;
unsigned char light;
float distance;
float time;
};
struct ControlMsgChangeBS
{
long long utime;
double throttle;
double brake;
double steeringRate;
double steeringTarget;
double speed;
double acceleration;
bool engineOnOff;
bool leftTurn;
bool rightTurn;
bool horn;
bool parkingBrake;
bool resetModel;
short drivingMode;
short gearLocation;
};
UDP服务端server与客户端client类的封装
#include "UDPClient.h"
#include <iostream>
using namespace std;
UDPClient::UDPClient(const char name[14])
{
WSAStartup(MAKEWORD(2, 2), &ws);
clientSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
std::cout << "**********************************************************" << std::endl;
cout << name << " Client Socket initialized Successful" << endl;
std::cout << "**********************************************************" << std::endl;
std::cout << std::endl;
}
UDPClient::~UDPClient()
{
closesocket(clientSocket);
WSACleanup();
cout << "Client Socket released" << endl;
}
void UDPClient::setSockAddr(char *destAddr,int destPort)
{
clientSockAddr.sin_family = AF_INET;
clientSockAddr.sin_port = htons(destPort);
clientSockAddr.sin_addr.s_addr = inet_addr(destAddr);
}
void UDPClient::sendData(char *buf,int len)
{
sendto(clientSocket, buf, len, 0, (SOCKADDR*)&clientSockAddr, sizeof(clientSockAddr));
}
#pragma once
#include <WINSOCK2.H>
#pragma comment(lib, "WS2_32.lib")
using namespace std;
class UDPClient
{
private:
WSADATA ws;
SOCKET clientSocket;
SOCKADDR_IN clientSockAddr;
public:
UDPClient(const char name[14]);
void setSockAddr(char *destAddr,int destPort);
void sendData(char *buf,int len);
~UDPClient();
};
#include"UDPServer.h"
#include<iostream>
using namespace std;
UDPServer::UDPServer()
{
WSAStartup(MAKEWORD(2, 2), &wsaData);
serverSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
}
void UDPServer::listen(int port,const char name[14])
{
serverSockAddr.sin_family = AF_INET;
serverSockAddr.sin_port = htons(port);
serverSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(serverSocket, (SOCKADDR*)&serverSockAddr, sizeof(serverSockAddr)) == 0)
{
std::cout << "**********************************************************" << std::endl;
cout << name << " Server Socket initialized Successful" << endl;
std::cout << "**********************************************************" << std::endl;
std::cout << std::endl;
}
else
{
std::cout << "**********************************************************" << std::endl;
cout << name << "Server Socket initialized Failed" << endl;
std::cout << "**********************************************************" << std::endl;
std::cout << std::endl;
}
}
void UDPServer::receive(char *buf,int len)
{
int serverSockAddrSize = sizeof(SOCKADDR);
recvfrom(serverSocket, buf, len, 0, (SOCKADDR *)&serverSockAddr, &serverSockAddrSize);
}
UDPServer::~UDPServer()
{
closesocket(serverSocket);
WSACleanup();
cout << "Server Socket released" << endl;
}
#pragma once
#include <WINSOCK2.H>
#pragma comment(lib, "WS2_32.lib")
using namespace std;
class UDPServer
{
private:
WSADATA wsaData;
SOCKET serverSocket;
sockaddr_in serverSockAddr;
public:
UDPServer();
void listen(int port, const char name[14]);
void receive(char *buf,int len);
~UDPServer();
};
初始化IP与Port的配置文件(ini格式)的封装
- 网上当的ini读取配置文件功能,包括inifile.h头文件和infile.cpp源文件加载即可,程序比较长就不做展示了.
- SimulatorDataExchange.ini
;UDPSend IP or Port
[UdpCarMsgReceive]
IP=127.0.0.1
Port=8025
[UdpCarMsgSend]
IP=127.0.0.1
Port=8029
[UdpGpsMsgReceive]
IP=127.0.0.1
Port=8026
[UdpControlMsgReceive]
IP=127.0.0.1
Port=8027
[UdpControlMsgSend]
IP=127.0.0.1
Port=8027
void readINI()
{
std::cout << "**********************************************************" << std::endl;
std::cout << " SIMULATOR DATA OF UDP RECEIVE AND SEND " << std::endl;
std::cout << "**********************************************************" << std::endl;
std::cout << std::endl;
CIniFileA ini;
ini.Load("SimulatorDataExchange.ini");
std::string carReceiveIP = ini.GetKeyValue("UdpCarMsgReceive", "IP");
strcpy(ip_ReceiveCarMsg, carReceiveIP.c_str());
std::string carReceivePort = ini.GetKeyValue("UdpCarMsgReceive", "Port");
port_ReceiveCarMsg = std::atoi(carReceivePort.c_str());
std::string carSendIP = ini.GetKeyValue("UdpCarMsgSend", "IP");
strcpy(ip_SendCarMsg, carSendIP.c_str());
std::string carSendPort = ini.GetKeyValue("UdpCarMsgSend", "Port");
port_SendCarMsg = std::atoi(carSendPort.c_str());
std::string gpsIP = ini.GetKeyValue("UdpGpsMsgReceive","IP");
strcpy(ip_ReceiveGPSMsg, gpsIP.c_str());
std::string gpsPort = ini.GetKeyValue("UdpGpsMsgReceive", "Port");
port_ReceiveGPSMsg = std::atoi(gpsPort.c_str());
std::string controlReceiveIP = ini.GetKeyValue("UdpControlMsgReceive", "IP");
strcpy(ip_ReceiveControlMsg, controlReceiveIP.c_str());
std::string controlReceivePort = ini.GetKeyValue("UdpControlMsgReceive", "Port");
port_ReceiveControlMsg = std::atoi(controlReceivePort.c_str());
std::string controlSendIP = ini.GetKeyValue("UdpControlMsgSend", "IP");
strcpy(ip_SendControlMsg, controlSendIP.c_str());
std::string controlSendPort = ini.GetKeyValue("UdpControlMsgSend", "Port");
port_SendControlMsg = std::atoi(controlSendPort.c_str());
if (!ip_ReceiveCarMsg && !port_ReceiveCarMsg && !ip_SendCarMsg && !port_SendCarMsg)
{
std::cout << "**********************************************************" << std::endl;
std::cout << " CONFIGURE COMMUNICATION IP AND PORT FAILED " << std::endl;
std::cout << "**********************************************************" << std::endl;
}
else
{
std::cout << "**********************************************************" << std::endl;
std::cout << " CONFIGURE COMMUNICATION IP AND PORT SUCCESS " << std::endl;
std::cout << "**********************************************************" << std::endl;
}
}
大小端转换类的封装
#include "stdafx.h"
#include "ChangeBS.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
CChangeBS::CChangeBS()
{
}
CChangeBS::~CChangeBS()
{
}
void CChangeBS::OnChange(short InParam, short &OutParam)
{
union
{
char ch[2];
unsigned short iTemp;
}u,r;
u.iTemp = InParam;
r.ch[0] = u.ch[1];
r.ch[1] = u.ch[0];
OutParam = r.iTemp;
}
void CChangeBS::OnChange(int InParam, int &OutParam)
{
union
{
char ch[4];
int iTemp;
}u,r;
u.iTemp = InParam;
r.ch[0] = u.ch[3];
r.ch[1] = u.ch[2];
r.ch[2] = u.ch[1];
r.ch[3] = u.ch[0];
OutParam = r.iTemp;
}
void CChangeBS::OnChange(float InParam, float &OutParam)
{
union
{
char ch[4];
float iTemp;
}u,r;
u.iTemp = InParam;
r.ch[0] = u.ch[3];
r.ch[1] = u.ch[2];
r.ch[2] = u.ch[1];
r.ch[3] = u.ch[0];
OutParam = r.iTemp;
}
void CChangeBS::OnChange(double InParam, double &OutParam)
{
union
{
char ch[8];
double iTemp;
}u,r;
u.iTemp = InParam;
r.ch[0] = u.ch[7];
r.ch[1] = u.ch[6];
r.ch[2] = u.ch[5];
r.ch[3] = u.ch[4];
r.ch[4] = u.ch[3];
r.ch[5] = u.ch[2];
r.ch[6] = u.ch[1];
r.ch[7] = u.ch[0];
OutParam = r.iTemp;
}
void CChangeBS::OnChange(long long InParam, long long &OutParam)
{
union
{
char ch[8];
long long iTemp;
}u, r;
u.iTemp = InParam;
r.ch[0] = u.ch[7];
r.ch[1] = u.ch[6];
r.ch[2] = u.ch[5];
r.ch[3] = u.ch[4];
r.ch[4] = u.ch[3];
r.ch[5] = u.ch[2];
r.ch[6] = u.ch[1];
r.ch[7] = u.ch[0];
OutParam = r.iTemp;
}
#if !defined(AFX_CHANGEBS_H__A852EEC4_2B3E_431B_B522_12BA81B648DA__INCLUDED_)
#define AFX_CHANGEBS_H__A852EEC4_2B3E_431B_B522_12BA81B648DA__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif
class CChangeBS
{
public:
CChangeBS();
virtual ~CChangeBS();
public:
static void OnChange(short InParam, short &OutParam);
static void OnChange(int InParam, int &OutParam);
static void OnChange(float InParam, float &OutParam);
static void OnChange(double InParam, double &OutParam);
static void OnChange(long long InParam, long long &OutParam);
};
#endif
主函数的介绍与使用
- SimulatorDataExchange.cpp
#include "chassis.pb.h"
#include "drive_state.pb.h"
#include "error_code.pb.h"
#include "geometry.pb.h"
#include "header.pb.h"
#include "vehicle_signal.pb.h"
#include "control_cmd.pb.h"
#include "pad_msg.pb.h"
#include "UDPClient.h"
#include "UDPServer.h"
#include "inifile.h"
#include "Message.h"
#include "ChangeBS.h"
#include <time.h>
#include <string.h>
#include <thread>
#include <iostream>
char ip1[12] = { NULL };
char ip2[12] = { NULL };
char ip3[12] = { NULL };
char ip4[12] = { NULL };
char ip5[12] = { NULL };
char* ip_ReceiveCarMsg = ip1;
int port_ReceiveCarMsg = NULL;
const int buffer_ReceiveCarMsg = 1024;
char* ip_SendCarMsg = ip2;
int port_SendCarMsg = NULL;
const int buffer_SendCarMsg = 1024;
char* ip_SendControlMsg = ip3;
int port_SendControlMsg = NULL;
const int buffer_SendControlMsg = 1024;
char* ip_ReceiveControlMsg = ip4;
int port_ReceiveControlMsg = NULL;
const int buffer_ReceiveControlMsg = 1024;
char* ip_ReceiveGPSMsg = ip5;
int port_ReceiveGPSMsg = NULL;
const int buffer_ReceiveGPSMsg = 1024;
CarMsg carmsg;
ControlMsg controlmsg;
ControlMsgChangeBS bs;
readINI()
{
std::cout << "**********************************************************" << std::endl;
std::cout << " SIMULATOR DATA OF UDP RECEIVE AND SEND " << std::endl;
std::cout << "**********************************************************" << std::endl;
std::cout << std::endl;
CIniFileA ini;
ini.Load("SimulatorDataExchange.ini");
std::string carReceiveIP = ini.GetKeyValue("UdpCarMsgReceive", "IP");
strcpy(ip_ReceiveCarMsg, carReceiveIP.c_str());
std::string carReceivePort = ini.GetKeyValue("UdpCarMsgReceive", "Port");
port_ReceiveCarMsg = std::atoi(carReceivePort.c_str());
std::string carSendIP = ini.GetKeyValue("UdpCarMsgSend", "IP");
strcpy(ip_SendCarMsg, carSendIP.c_str());
std::string carSendPort = ini.GetKeyValue("UdpCarMsgSend", "Port");
port_SendCarMsg = std::atoi(carSendPort.c_str());
std::string gpsIP = ini.GetKeyValue("UdpGpsMsgReceive","IP");
strcpy(ip_ReceiveGPSMsg, gpsIP.c_str());
std::string gpsPort = ini.GetKeyValue("UdpGpsMsgReceive", "Port");
port_ReceiveGPSMsg = std::atoi(gpsPort.c_str());
std::string controlReceiveIP = ini.GetKeyValue("UdpControlMsgReceive", "IP");
strcpy(ip_ReceiveControlMsg, controlReceiveIP.c_str());
std::string controlReceivePort = ini.GetKeyValue("UdpControlMsgReceive", "Port");
port_ReceiveControlMsg = std::atoi(controlReceivePort.c_str());
std::string controlSendIP = ini.GetKeyValue("UdpControlMsgSend", "IP");
strcpy(ip_SendControlMsg, controlSendIP.c_str());
std::string controlSendPort = ini.GetKeyValue("UdpControlMsgSend", "Port");
port_SendControlMsg = std::atoi(controlSendPort.c_str());
if (!ip_ReceiveCarMsg && !port_ReceiveCarMsg && !ip_SendCarMsg && !port_SendCarMsg)
{
std::cout << "**********************************************************" << std::endl;
std::cout << " CONFIGURE COMMUNICATION IP AND PORT FAILED " << std::endl;
std::cout << "**********************************************************" << std::endl;
}
else
{
std::cout << "**********************************************************" << std::endl;
std::cout << " CONFIGURE COMMUNICATION IP AND PORT SUCCESS " << std::endl;
std::cout << "**********************************************************" << std::endl;
}
}
void carMsgReceive(int port,const char name[14])
{
char receivebuff[buffer_ReceiveCarMsg] = { 0 };
UDPServer* server = new UDPServer;
server->listen(port,name);
while (true)
{
server->receive(receivebuff, sizeof(receivebuff));
memcpy(&carmsg.utime,&receivebuff[0],8);
memcpy(&carmsg.nauto,&receivebuff[8],4);
memcpy(&carmsg.steerPos, &receivebuff[12],4);
memcpy(&carmsg.steerSpe, &receivebuff[16], 4);
memcpy(&carmsg.light, &receivebuff[20], 4);
memcpy(&carmsg.speLeft, &receivebuff[24], 4);
memcpy(&carmsg.speRight, &receivebuff[28], 4);
memcpy(&carmsg.vot, &receivebuff[32], 4);
memcpy(&carmsg.shift, &receivebuff[36], 4);
memcpy(&carmsg.disLeft, &receivebuff[40], 4);
memcpy(&carmsg.disRight, &receivebuff[44], 4);
memcpy(&carmsg.speo, &receivebuff[48], 4);
memcpy(&carmsg.yawRate, &receivebuff[52], 4);
memcpy(&carmsg.accelerationLon, &receivebuff[56], 4);
memcpy(&carmsg.accelerationLat, &receivebuff[60], 4);
std::cout << "CarMsg:" << carmsg.utime <<std::endl;
}
delete server;
std::cout << "ReceiveCarMsg Server Destroyed" << std::endl;
}
void controlMsgReceive(int port, const char name[14])
{
char receivebuff[buffer_ReceiveControlMsg] = { 0 };
UDPServer* server = new UDPServer;
server->listen(port, name);
ab::control::ControlCommand *control = new ab::control::ControlCommand();
while (true)
{
server->receive(receivebuff, sizeof(receivebuff));
control->ParseFromArray(receivebuff, sizeof(receivebuff));
controlmsg.throttle = control->throttle();
controlmsg.brake = control->brake();
controlmsg.steeringRate = control->steering_rate();
controlmsg.steeringTarget = control->steering_target() * 520;
controlmsg.speed = control->speed();
controlmsg.acceleration = control->acceleration();
controlmsg.engineOnOff = control->engine_on_off();
controlmsg.parkingBrake = control->parking_brake();
controlmsg.horn = control->horn();
controlmsg.resetModel = control->reset_model();
int turn = control->turnsignal();
if (turn == 0)
{
controlmsg.leftTurn = 0;
controlmsg.rightTurn = 0;
}
else if (turn == 1)
{
controlmsg.leftTurn = 1;
controlmsg.rightTurn = 0;
}
else
{
controlmsg.leftTurn = 0;
controlmsg.rightTurn = 1;
}
controlmsg.drivingMode = control->driving_mode();
controlmsg.gearLocation = control->gear_location();
}
delete server;
std::cout << "ReceiveControlMsg Server Destroyed" << std::endl;
}
void carMsgSend(const int port,char *address, float time, const char name[14])
{
char sendbuff[buffer_SendCarMsg] = { 0 };
clock_t start, end;
start = clock();
UDPClient* client = new UDPClient(name);
client->setSockAddr(address, port);
ab::vehicle::Chassis *carmsg_send = new ab::vehicle::Chassis();
ab::common::VehicleSignal *vehiclesignal = new ab::common::VehicleSignal();
while (true)
{
carmsg_send->set_steering_timestamp(carmsg.utime);
carmsg_send->set_driving_mode(ab::vehicle::Chassis_DrivingMode(carmsg.nauto));
carmsg_send->set_gear_location(ab::vehicle::Chassis_GearPosition(carmsg.shift));
carmsg_send->set_steering_percentage(carmsg.steerPos/520);
vehiclesignal->set_turn_signal(ab::common::VehicleSignal_TurnSignal(carmsg.light));
carmsg_send->set_speed_mps((carmsg.speLeft+carmsg.speRight)/7.2);
carmsg_send->SerializeToArray(sendbuff, sizeof(sendbuff));
end = clock();
if (end - start > time)
{
client->sendData(sendbuff, sizeof(sendbuff));
start = end;
}
Sleep(1);
}
delete client;
}
void controlMsgSend(const int port, char *address, float time, const char name[14])
{
char sendbuff[buffer_SendControlMsg] = { 0 };
clock_t start, end;
start = clock();
UDPClient* client = new UDPClient(name);
client->setSockAddr(address, port);
while (true)
{
CChangeBS::OnChange(controlmsg.utime, bs.utime);
CChangeBS::OnChange(controlmsg.throttle, bs.throttle);
CChangeBS::OnChange(controlmsg.brake, bs.brake);
CChangeBS::OnChange(controlmsg.steeringRate, bs.steeringRate);
CChangeBS::OnChange(controlmsg.steeringTarget, bs.steeringTarget);
CChangeBS::OnChange(controlmsg.speed, bs.speed);
CChangeBS::OnChange(controlmsg.acceleration, bs.acceleration);
bs.engineOnOff = controlmsg.engineOnOff;
bs.leftTurn = controlmsg.leftTurn;
bs.rightTurn = controlmsg.rightTurn;
bs.horn = controlmsg.horn;
bs.parkingBrake = controlmsg.parkingBrake;
bs.resetModel = controlmsg.resetModel;
CChangeBS::OnChange(controlmsg.drivingMode, bs.drivingMode);
CChangeBS::OnChange(controlmsg.gearLocation, bs.gearLocation);
char* pack = (char *)&bs;
end = clock();
if (end - start > time)
{
client->sendData(pack, sizeof(sendbuff));
start = end;
}
Sleep(1);
}
delete client;
}
int main(int argc, char *argv[])
{
readINI();
std::thread udpReceiveCarMsg(carMsgReceive, port_ReceiveCarMsg, "ReceiveCarMsg");
udpReceiveCarMsg.detach();
std::thread udpSendCarMsg(carMsgSend, port_SendCarMsg, ip_SendCarMsg,99, "SendCarMsg");
udpSendCarMsg.detach();
std::thread udpReceiveControlMsg(controlMsgReceive, port_ReceiveControlMsg, "ReceiveControlMsg");
udpReceiveControlMsg.detach();
std::thread udpSendControlMsg(controlMsgSend, port_SendControlMsg, ip_SendControlMsg, 99, "SendControlMsg");
udpSendControlMsg.detach();
while (true)
{
Sleep(100);
}
}
另一台电脑调用
- VS2017编译后会生成exe可执行文件,注意将SimulatorDataExchange.ini配置文件放在exe文件夹下面,同一目录
- 其他的ilk文件和pdb文件也要放在一起,这是打包的头文件和资源文件等压缩的.

- 运行效果
