UDPマルチキャストが便利すぎる
UDPは一斉送信できるのは知っていましたが、いままで一度も使ったことがありませんでした。
で、今回試してみたら、メチャクチャ便利だなぁ、と実感しましたので、自分の為にコードを残しておきます。
受信側の「SO_REUSEADDRオプションを設定」がキモです。"bind: Address already in use"の呪いを受けなくてもすみます。
udp_multicast_send に対して、複数個のudp_multicast_recv でメッセージ受信できます。
(送信側) udp_multicast_send.c
#include <stdio.h>
/*
gcc -o udp_multicast_send udp_multicast_send.c
*/
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MULTICAST_GROUP "239.0.0.1"
#define MULTICAST_PORT 12345
void receive_process_count() {
int sock;
struct sockaddr_in addr;
struct ip_mreq mreq;
char message[256];
// ソケットの作成
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("socket");
exit(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(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
perror("bind");
exit(1);
}
// マルチキャストグループに参加
mreq.imr_multiaddr.s_addr = inet_addr(MULTICAST_GROUP);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
perror("setsockopt");
exit(1);
}
// メッセージの受信
while (1) {
int nbytes = recv(sock, message, sizeof(message), 0);
if (nbytes < 0) {
perror("recv");
exit(1);
}
message[nbytes] = '\0';
printf("Received process count: %s\n", message);
}
}
int main() {
printf("abc_vtp_0.2 process started. Waiting for process count...\n");
receive_process_count();
return 0;
}
(受信側) udp_multicast_recv.c
/* gcc -o udp_multicast_recv udp_multicast_recv.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MULTICAST_GROUP "239.0.0.1"
#define MULTICAST_PORT 12345
void receive_process_count() {
int sock;
struct sockaddr_in addr;
struct ip_mreq mreq;
char message[256];
// ソケットの作成
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("socket");
exit(1);
}
// SO_REUSEADDRオプションを設定
int reuse = 1;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0) {
perror("Setting SO_REUSEADDR error");
close(sock);
exit(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(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
perror("bind");
exit(1);
}
// マルチキャストグループに参加
mreq.imr_multiaddr.s_addr = inet_addr(MULTICAST_GROUP);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
perror("setsockopt");
exit(1);
}
// メッセージの受信
while (1) {
int nbytes = recv(sock, message, sizeof(message), 0);
if (nbytes < 0) {
perror("recv");
exit(1);
}
message[nbytes] = '\0';
printf("Received process count: %s\n", message);
}
}
int main() {
printf("abc_vtp_0.2 process started. Waiting for process count...\n");
receive_process_count();
return 0;
}