Narzędzia użytkownika

Narzędzia witryny


sk2:multicast_example

Różnice

Różnice między wybraną wersją a wersją aktualną.

Odnośnik do tego porównania

Both sides previous revision Poprzednia wersja
sk2:multicast_example [2021/12/20 13:49]
jkonczak
sk2:multicast_example [2025/11/27 19:49] (aktualna)
jkonczak
Linia 1: Linia 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
Linia 28: Linia 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.txt · ostatnio zmienione: 2025/11/27 19:49 przez jkonczak