User Tools

Site Tools


sk2:multicast_example

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
sk2:multicast_example [2021/12/20 12:49] – jkonczaksk2:multicast_example [2025/11/27 18:49] (current) – jkonczak
Line 1: Line 1:
 ==== Przykład użycia UDP multicast ==== ==== Przykład użycia UDP multicast ====
 <code cpp multicast_example.cpp> <code cpp multicast_example.cpp>
 +#include <csignal>
 +#include <cstdio>
 #include <cstdlib> #include <cstdlib>
-#include <cstdio> 
-#include <csignal> 
  
-#include <thread> 
 #include <atomic> #include <atomic>
 +#include <thread>
  
-#include <unistd.h> 
 #include <errno.h> #include <errno.h>
 #include <error.h> #include <error.h>
 +#include <unistd.h>
  
-#include <sys/socket.h> 
-#include <netinet/ip.h> 
 #include <arpa/inet.h> #include <arpa/inet.h>
 +#include <netinet/ip.h>
 +#include <sys/socket.h>
  
 /* UDP multicast example. Compile with threads and C++11 (g++ -pthread --std=c++11) /* UDP multicast example. Compile with threads and C++11 (g++ -pthread --std=c++11)
- * + *
  * Sending to multicast group MCASTIP:MCASTPORT  * Sending to multicast group MCASTIP:MCASTPORT
  *   - create a UDP socket  *   - create a UDP socket
  *   - send a datagram to MCASTIP:MCASTPORT  *   - send a datagram to MCASTIP:MCASTPORT
- * + *
  * Receiving datagrams sent to a multicast group MCASTIP:MCASTPORT  * Receiving datagrams sent to a multicast group MCASTIP:MCASTPORT
  *   - create a UDP socket  *   - create a UDP socket
Line 28: Line 28:
  *   - call setsockopt to set option IP_ADD_MEMBERSHIP on level IPPROTO_IP to the aforementioned structure  *   - call setsockopt to set option IP_ADD_MEMBERSHIP on level IPPROTO_IP to the aforementioned structure
  *   - receive datagrams  *   - receive datagrams
- * + *
  * setsockopt of IP_ADD_MEMBERSHIP sends an IGMP message "join group" and tells OS that the program waits for messages for the group.  * setsockopt of IP_ADD_MEMBERSHIP sends an IGMP message "join group" and tells OS that the program waits for messages for the group.
- * + *
  * More info at: https://tldp.org/HOWTO/Multicast-HOWTO-6.html  * More info at: https://tldp.org/HOWTO/Multicast-HOWTO-6.html
  */  */
  
- +const sockaddr_in groupSockaddr{ 
-const sockaddr_in groupSockaddr { +    .sin_family = AF_INET, 
- .sin_family = AF_INET, +    .sin_port = htons(6789), 
- .sin_port = htons(6789), +    .sin_addr = {.s_addr = inet_addr("239.255.123.45")}
- .sin_addr = {inet_addr("239.255.123.45")}+
 }; };
  
-std::atomic<bool> quitting {false};+std::atomic<bool> quitting{false};
  
-void ctrl_c(int){ +void ctrl_c(int) { 
- if(quitting) +    if (quitting) 
- exit(-1); +        exit(-1); 
- quitting = true;+    quitting = true;
 } }
  
 void setupSignals(); void setupSignals();
  
-int main(int argc, char **argv) { +int main() { 
-  + 
- // create socket +    // create socket 
- int sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); +    int sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 
- if(sockfd==-1) error(1,errno, "socket"); +    if (sockfd == -1) 
-  +        error(1, errno, "socket"); 
- // set SO_REUSEADDR (or only one app will be allowed to receive multicast messages from the groupIP:port pair) + 
- // this is one of very few cases when SO_REUSEADDR on UDP has any use +    // set SO_REUSEADDR (or only one app will be allowed to receive multicast messages from the groupIP:port pair) 
- const int one = 1; +    const int one = 1; 
- int res = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); +    int res = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); 
- if(res) error(1,errno, "setsockopt SO_REUSEADDR"); +    if (res) 
-  +        error(1, errno, "setsockopt SO_REUSEADDR"); 
- // bind  + 
- sockaddr_in myAddress { +    // bind 
- .sin_family = AF_INET, +    sockaddr_in myAddress{ 
- .sin_port = groupSockaddr.sin_port, +        .sin_family = AF_INET, 
- .sin_addr = {INADDR_ANY} +        .sin_port = groupSockaddr.sin_port, 
- }; +        .sin_addr = {INADDR_ANY} 
- res = bind(sockfd, (sockaddr*) &myAddress, sizeof(myAddress)); +    }; 
- if(res) error(1, errno, "bind"); +    res = bind(sockfd, (sockaddr *)&myAddress, sizeof(myAddress)); 
-  +    if (res) 
- // send IGMP join group +        error(1, errno, "bind"); 
- ip_mreqn groupDescription{ + 
- .imr_multiaddr = groupSockaddr.sin_addr, +    // send IGMP join group 
- .imr_address =  {INADDR_ANY}, +    ip_mreqn groupDescription{ 
- .imr_ifindex = 0 +        .imr_multiaddr = groupSockaddr.sin_addr, 
- }; +        .imr_address = {INADDR_ANY}, 
- auto ret = setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &groupDescription, sizeof(groupDescription)); +        .imr_ifindex = 0 
- if(ret) error(1, errno, "setsockopt IP_ADD_MEMBERSHIP"); +    }; 
-  +    auto ret = setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &groupDescription, sizeof(groupDescription)); 
- // handle ctrl+c for gracefull exit +    if (ret) 
- setupSignals(); +        error(1, errno, "setsockopt IP_ADD_MEMBERSHIP"); 
-  + 
- // receive and display ANY packet that arrives +    // handle ctrl+c for gracefull exit 
- std::thread readerThread([&]{ +    setupSignals(); 
- sockaddr_in peerAddr; + 
- socklen_t peerAddrSize; +    // receive and display ANY packet that arrives 
- char buffer[255]; +    std::thread readerThread([&] { 
- while(true){ +        sockaddr_in peerAddr; 
- peerAddrSize = sizeof(peerAddr); +        socklen_t peerAddrSize; 
- auto readSize = recvfrom(sockfd, buffer, 254, MSG_TRUNC, (sockaddr*) &peerAddr, &peerAddrSize); +        char buffer[255]; 
- if(quitting) break; +        while (true) { 
- if(readSize==-1) error(1,errno, "recvfrom"); +            peerAddrSize = sizeof(peerAddr); 
- if(readSize>254) { error(0,0,"UDP packet too long - truncated from %ld to %d", readSize, 254); readSize=254;} +            auto readSize = recvfrom(sockfd, buffer, 254, MSG_TRUNC, (sockaddr *)&peerAddr, &peerAddrSize); 
- buffer[readSize] = 0; +            if (quitting) 
- printf("<%s:%hu> %s", inet_ntoa(peerAddr.sin_addr), ntohs(peerAddr.sin_port), buffer); +                break; 
- } +            if (readSize == -1) 
- }); +                error(1, errno, "recvfrom"); 
-  +            if (readSize > 254) { 
- // read standard input and send it to the group +                error(0, 0, "UDP packet too long - truncated from %ld to %d", readSize, 254); 
- char buffer[255]; +                readSize = 254; 
- while(true){ +            } 
- auto readSize = read(0, buffer, 254); +            buffer[readSize] = 0; 
- if(quitting || !readSize) break; +            printf("<%s:%hu> %s", inet_ntoa(peerAddr.sin_addr), ntohs(peerAddr.sin_port), buffer); 
- if(readSize<0) { error(0, errno, "reading stdin"); break; } +        } 
-  +    }); 
- auto res = sendto(sockfd, buffer, readSize, 0, (sockaddr*) &groupSockaddr, sizeof(groupSockaddr)); + 
- if(res!=readSize) { error(0,  errno, "sendto"); break; } +    // read standard input and send it to the group 
- } +    char buffer[255]; 
-  +    while (true) { 
- quitting = true; +        auto readSize = read(0, buffer, 254); 
- // leave group +        if (quitting || !readSize) 
- setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &groupDescription, sizeof(groupDescription)); +            break; 
- // close socket AND interrupt all blocked recvfrom  +        if (readSize < 0) { 
- shutdown(sockfd, SHUT_RDWR); +            error(0, errno, "reading stdin"); 
- close(sockfd); +            break; 
- // wait for child +        } 
- readerThread.join(); + 
-  +        auto res = sendto(sockfd, buffer, readSize, 0, (sockaddr *)&groupSockaddr, sizeof(groupSockaddr)); 
- return 0;+        if (res != readSize) { 
 +            error(0, errno, "sendto"); 
 +            break; 
 +        } 
 +    } 
 + 
 +    quitting = true; 
 +    // leave group 
 +    setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &groupDescription, sizeof(groupDescription)); 
 +    // close socket AND interrupt all blocked recvfrom 
 +    shutdown(sockfd, SHUT_RDWR); 
 +    close(sockfd); 
 +    // wait for child 
 +    readerThread.join(); 
 + 
 +    return 0;
 } }
  
-void setupSignals(){ +void setupSignals() { 
- struct sigaction action; +    struct sigaction action; 
-  + 
- // read sigint handler description +    // read sigint handler description 
- auto res = sigaction(SIGINT, nullptr, &action); +    auto res = sigaction(SIGINT, nullptr, &action); 
- if(res) error(1, errno, "sigaction read"); +    if (res) 
-  +        error(1, errno, "sigaction read"); 
- // set new interrupt handler + 
- action.sa_handler = ctrl_c; +    // set new interrupt handler 
- // disable SA_RESTART flag to exit blocking IO upon a signal +    action.sa_handler = ctrl_c; 
- action.sa_flags &= ~SA_RESTART; +    // disable SA_RESTART flag to exit blocking IO upon a signal 
-  +    action.sa_flags &= ~SA_RESTART; 
- // update sigint handler description + 
- res = sigaction(SIGINT, &action, nullptr); +    // update sigint handler description 
- if(res) error(1, errno, "sigaction modify");+    res = sigaction(SIGINT, &action, nullptr); 
 +    if (res) 
 +        error(1, errno, "sigaction modify");
 } }
 </code> </code>
sk2/multicast_example.1640004573.txt.gz · Last modified: (external edit)