原因不多说,目录结构扁平,
data.h如下:
#pragma once
#include <cstring>
#include <cstdint>
#include <sys/types.h>
#define MULTICAST_IP "234.0.0.1"
#define MULTICAST_PORT 28928
#pragma pack(1)
typedef struct price {
int64_t mantissa;
int64_t exponent;
} PriceType;
struct Sse_MarketData_Stock
{
Sse_MarketData_Stock()
{
memset(this,0,sizeof(Sse_MarketData_Stock));
}
uint64_t seq_num;
u_char MdStreamID[8];
u_char Timestamp[8];
u_char SecutrityID[8];
u_char Symbol[8];
uint64_t TradeVolume;
PriceType TotalValueTraded;
PriceType PreClosePrice;
PriceType PrevSetPrice;
uint64_t TotalLongPosition;
PriceType IndexValue;
PriceType OpenPrice;
PriceType ClosePrice;
PriceType HighPrice;
PriceType LowPrice;
u_char TradingPhaseCode[8];
u_char reserved[24];
};
#pragma pack()
multi_cast_send.cpp如下:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>
#include <iostream>
#include <thread>
#include <chrono>
#include <string>
#include "data.h"
using namespace std;
int main(int argc, char *argv[])
{
struct sockaddr_in mcast_addr;
int fd;
Sse_MarketData_Stock data;
data.seq_num=1;
strcpy((char*)data.MdStreamID,"MD001");
strcpy((char*)data.SecutrityID,"10002231");
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket");
return -1;
}
memset(&mcast_addr, 0, sizeof(mcast_addr));
mcast_addr.sin_family = AF_INET;
mcast_addr.sin_addr.s_addr = inet_addr(MULTICAST_IP);
mcast_addr.sin_port = htons(MULTICAST_PORT);
do{
data.seq_num++;
if (sendto(fd, reinterpret_cast<const char *>(&data), sizeof(data), 0, (struct sockaddr *)&mcast_addr, sizeof(mcast_addr)) < 0)
{
perror("sendto");
return -1;
}
cout<<"send to["<<MULTICAST_IP<<":"<<MULTICAST_PORT<<"] ok,seq_num="<<data.seq_num<<endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}while(true);
setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mcast_addr, sizeof(mcast_addr));
close(fd);
return 0;
}
multi_cast_recv.cpp如下:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <iostream>
#include <cstring>
#include "data.h"
using namespace std;
int main(int argc,char* argv[])
{
struct sockaddr_in addr;
int fd;
struct ip_mreq mreq;
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket ");
return -1;
}
int on = 1;
/* 设置地址复用许可, 根据具体情况判断是否增加此功能 */
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
{
perror("SO_REUSEADDR");
return -1;
}
/* 初始化地址 */
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(MULTICAST_PORT);
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("bind");
return -1;
}
/*加入多播组*/
mreq.imr_multiaddr.s_addr = inet_addr(MULTICAST_IP);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
{
perror("setsockopt");
return -1;
}
int addrlen = sizeof(addr);
Sse_MarketData_Stock recv_data;
int nbytes;
while(true){
if ((nbytes = recvfrom(fd,reinterpret_cast<char*>(&recv_data),sizeof(Sse_MarketData_Stock), 0, (struct sockaddr *)&addr, (socklen_t *)&addrlen)) < 0)
{
perror("recvfrom");
break;
}
cout<<"recv from ["<<MULTICAST_IP<<":"<<MULTICAST_PORT<<"]"<<recv_data.seq_num<<":"<<recv_data.SecutrityID<<endl;
}
/*退出多播组*/
setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
close(fd);
return 0;
}
最后,CMakeLists.txt如下:
cmake_minimum_required( VERSION 3.8 FATAL_ERROR)
project(main VERSION 1.0.0 LANGUAGES CXX)
SET(CMAKE_EXPORT_COMPILE_COMMANDS ON)
#set dirs
SET(PROJECT_ROOT ${CMAKE_CURRENT_LIST_DIR})
message("project dir:${PROJECT_ROOT}")
SET(BIN_DESTINATION ${PROJECT_SOURCE_DIR}/bin)
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${BIN_DESTINATION})
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${BIN_DESTINATION})
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BIN_DESTINATION})
#set compile flags
set(CMAKE_CXX_FLAGS "-g3 -rdynamic -std=c++11")
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -fsanitize=address -fno-omit-frame-pointer -fsanitize=leak")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
#include dirs
include_directories(./)
#link dirs
link_directories(${BIN_DESTINATION})
#execute
SET(SEND_SRC multi_cast_send.cpp)
add_executable(send ${SEND_SRC})
SET_TARGET_PROPERTIES(send PROPERTIES VERSION ${PROJECT_VERSION})
SET (RECV_SRC multi_cast_recv.cpp)
add_executable(recv ${RECV_SRC})
SET_TARGET_PROPERTIES(recv PROPERTIES VERSION ${PROJECT_VERSION})
在当前上当,创建build目录,进入build目录,执行:
cmake .. -DCMAKE_BUILD_TYPE=Debug && make clean && make VERBOSE=1
会在bin目录生成send和recv可执行文件,即可演示组播