udp组播示例(发送、接收)

原因不多说,目录结构扁平,

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可执行文件,即可演示组播

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ztenv

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值