2021年4月15日 星期四

在 linux 系統上接收 multicast 訊息的小程式

接收 multicast 位址  = 239.255.255.250, udp port = 1900 範例程式 mserver.c:

#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
int main( ) {
    static int fd = socket(AF_INET, SOCK_DGRAM, 0);// get file descriptor by opening udp
    if (fd < 0) return 1;// error

    signal(SIGINT, [ ](int sig) {// ctrl-C handler
        close(fd);
        printf("!!! to exit\n");
        exit(1);
    });

    int value = 1;// set option SO_REUSEADDR, value type must be int!
    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value)) == 0) {
        
        sockaddr_in addr = {
            .sin_family = AF_INET,
            .sin_port   = htons(1900),// udp port 1900
            .sin_addr   = {.s_addr = inet_addr("239.255.255.250")},// multicast only, or htonl(INADDR_ANY);
            .sin_zero   = {0}
        };
        ip_mreq req = {
            .imr_multiaddr = {.s_addr = addr.sin_addr},
            .imr_interface = {.s_addr = htonl(INADDR_ANY)} // any of local IF
        };
        sockaddr  *addrPtr = (sockaddr *)&addr;// cast to sockaddr pointer
        socklen_t addrSize = sizeof(addr);// cast to socklen_t

        if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &req, sizeof(req)) == 0 &&
            bind(fd, addrPtr, addrSize) == 0) {
                
            char buffer[256];
            int len = 0;
            do {// to receive message
                len = recv(fd, buffer, 255, 0);
                if (len > 0) {
                    buffer[len] = 0;
                    printf("%s\n", buffer);   
                }
            } while (len >= 0);
        }
    }
    close(fd);
    return 0;
}

編譯及執行:

   g++ mserver.c -o mserver && ./server 

傳送 multicast 位址  = 239.255.255.250, udp port = 1900 範例程式 mclient.c:

#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
int main( ) {
    static int fd = socket(AF_INET, SOCK_DGRAM, 0);// udp
    if (fd < 0) return 1;

    signal(SIGINT, [ ](int sig) {// ctrl-C handler
        close(fd);
        printf("!!! to exit\n");
        exit(1);
    });

    sockaddr_in addr = {
        .sin_family = AF_INET,
        .sin_port   = htons(1900),// udp port 1900
        .sin_addr   = {.s_addr = inet_addr("239.255.255.250")},
        .sin_zero   = {0}
    };
    sockaddr  *addrPtr = (sockaddr *)&addr;// cast to sockaddr pointer
    socklen_t addrSize = sizeof(addr);// cast to socklen_t 

    auto mcastSend = [&addrPtr, &addrSize](const char *msg) {
        printf("%s %d\n", msg, fd);
        return sendto(fd, msg, strlen(msg), 0, addrPtr, addrSize);
    };
    while (mcastSend("hello") >= 0) sleep(1);// wait 1 second to send again
    return 0;
}

開啟另一終端機, 編譯並執行:

   g++ mclient.c -o mclient && ./mclient

沒有留言:

張貼留言

使用 pcie 轉接器連接 nvme SSD

之前 AM4 主機板使用 pcie ssd, 但主機板故障了沒辦法上網, 只好翻出以前買的 FM2 舊主機板, 想辦法讓老主機復活, 但舊主機板沒有 nvme 的界面, 因此上網買了 pcie 轉接器用來連接 nvme ssd, 遺憾的是 grub2 bootloader 無法識...