UDP マルチキャスト ソケットを開くための非常に小さな C コードを作成しました。32 ビット プラットフォームでは問題なく動作しますが、コードを再コンパイルして Linux 64 ビット プラットフォームで試してみると、動作しません。プログラムは、recvfrom() 関数で無期限に保留されています。指定したネットワーク インターフェイスで udp フレームが実際に受信されたかどうかを tcpdump で確認しましたが、すべて正常に動作しています。私のコードの何が問題なのか、誰かが考えを持っていますか?
これが最初のコードです(コメントの前):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <math.h>
#include <errno.h>
static char* server = "231.180.0.1";
static char* network = "66.46.40.10";
static int port = 50001;
static struct sockaddr_in socketAddr;
static unsigned int socketDesc;
long toLong (unsigned char* msg, int offset);
int main (void) {
struct ip_mreq mreq;
int bindDesc, socketOptDesc;
int reuse = 1;
unsigned int socketLength = sizeof(socketAddr);
// Allocation
memset((char *) &socketAddr, 0, sizeof(socketAddr));
memset(&mreq, 0, sizeof(struct ip_mreq));
/*
* Create a datagram socket on which to receive.
*/
printf("# Init socket (server=%s network=%s port=%d)\n", server, network, port);
socketDesc = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (socketDesc < 0) {
perror("socket() failed");
} else {
/*
* Enable SO_REUSEADDR to allow multiple instances of this
* application to receive copies of the multicast datagrams.
*/
socketOptDesc = setsockopt(socketDesc, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(reuse));
if (socketOptDesc < 0) {
perror("setsockopt() failed");
} else {
/*
* Bind to the proper port number with the IP address
* specified as INADDR_ANY.
*/
socketAddr.sin_family = AF_INET;
socketAddr.sin_port = htons(port);
socketAddr.sin_addr.s_addr = INADDR_ANY;
bindDesc = bind(socketDesc, (struct sockaddr*) &socketAddr, sizeof(socketAddr));
if (bindDesc < 0) {
perror("bind() failed");
} else {
/*
* Join the multicast group on the local interface.
* Note that this IP_ADD_MEMBERSHIP option must be
* called for each local interface over which the multicast
* datagrams are to be received.
*/
mreq.imr_multiaddr.s_addr = inet_addr(server);
mreq.imr_interface.s_addr = inet_addr(network);
socketOptDesc = setsockopt(socketDesc, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq));
if (socketOptDesc < 0) {
perror("setsockopt() failed");
} else {
printf("# Socket created successfully !\n");
}
}
}
}
/*
* Acquisition Loop
*/
printf("# Starting reception loop...\n");
long lastFrameNumber = -1;
int nbDots = 0;
while (1) {
long frameNumber = -1;
unsigned char buffer[65536];
// Frame Acquisition
int ret = recvfrom(socketDesc, buffer, 65536, 0, (struct sockaddr *) &socketAddr, &socketLength);
if (ret < 0) {
perror("recvfrom() failed");
}
// Reading frame number
frameNumber = toLong(buffer, 28);
if (frameNumber < 0) {
// Context Frame
} else if (frameNumber == 0) {
printf("Invalid frame (frameNumber=0)\n");
} else {
if (frameNumber > 1 && frameNumber != (lastFrameNumber + 1)) {
printf("%ld frame(s) lost from frame %ld\n", frameNumber - lastFrameNumber - 1, lastFrameNumber + 1);
}
}
lastFrameNumber = frameNumber;
if (frameNumber == 1) {
if (nbDots > 50) {
printf(".\n");
nbDots = 0;
} else {
printf(".");
fflush(stdout);
}
nbDots++;
}
}
return EXIT_SUCCESS;
}
/* ======================================================================
* Read 4 bytes from the specified offset and convert it to a long value.
*
* @input msg
* Byte array representing the message.
* @input offset
* Byte offset.
* @return
* Long value representing the frame number.
* ====================================================================*/
long toLong (unsigned char* msg, int offset) {
long value;
int byte0; // bits 31..24
int byte1; // bits 23..16
int byte2; // bits 15..8
int byte3; // bits 7..0
byte0 = (0x000000FF & ((int) msg[offset + 0]));
byte1 = (0x000000FF & ((int) msg[offset + 1]));
byte2 = (0x000000FF & ((int) msg[offset + 2]));
byte3 = (0x000000FF & ((int) msg[offset + 3]));
value = ((long) (byte0 << 24 | byte1 << 16 | byte2 << 8 | byte3)) & 0xFFFFFFFFL;
return value;
}
編集:あなたのコメントでコードを更新しましたが、どちらも機能しません:(また、ネットワークがVLANを使用していることを忘れていました。ネットワークインターフェイスは66.46.40.100のeth.40ですが、32ビットプラットフォームで動作しますだから問題ないのかもしれません。
新しいコードは次のとおりです。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <math.h>
#include <errno.h>
static char* server = "231.180.0.1";
static char* network = "66.46.40.100";
static uint16_t port = 50001;
long toLong (unsigned char* msg, int offset);
int main (void) {
struct sockaddr_in socketAddr;
struct ip_mreq mreq;
int bindDesc, socketDesc, socketOptDesc;
socklen_t reuse = 1;
socklen_t socketLength = sizeof(socketAddr);
// Allocation
memset((char *) &socketAddr, 0, sizeof(socketAddr));
memset(&mreq, 0, sizeof(struct ip_mreq));
/*
* Create a datagram socket on which to receive.
*/
printf("# Init socket (server=%s network=%s port=%d)\n", server, network, port);
socketDesc = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (socketDesc < 0) {
perror("socket() failed");
} else {
/*
* Enable SO_REUSEADDR to allow multiple instances of this
* application to receive copies of the multicast datagrams.
*/
socketOptDesc = setsockopt(socketDesc, SOL_SOCKET, SO_REUSEADDR, (void *) &reuse, sizeof(reuse));
if (socketOptDesc < 0) {
perror("setsockopt() failed");
} else {
/*
* Bind to the proper port number with the IP address
* specified as INADDR_ANY.
*/
socketAddr.sin_family = AF_INET;
socketAddr.sin_port = htons(port);
socketAddr.sin_addr.s_addr = INADDR_ANY;
bindDesc = bind(socketDesc, (struct sockaddr*) &socketAddr, sizeof(socketAddr));
if (bindDesc < 0) {
perror("bind() failed");
} else {
/*
* Join the multicast group on the local interface.
* Note that this IP_ADD_MEMBERSHIP option must be
* called for each local interface over which the multicast
* datagrams are to be received.
*/
mreq.imr_multiaddr.s_addr = inet_addr(server);
mreq.imr_interface.s_addr = inet_addr(network);
socketOptDesc = setsockopt(socketDesc, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq));
if (socketOptDesc < 0) {
perror("setsockopt() failed");
} else {
printf("# Socket created successfully !\n");
}
}
}
}
/*
* Acquisition Loop
*/
printf("# Starting reception loop...\n");
long lastFrameNumber = -1;
int nbDots = 0;
while (1) {
unsigned char buffer[65536];
// Frame Acquisition
ssize_t ret = recvfrom(socketDesc, buffer, 65536, 0, (struct sockaddr *) &socketAddr, &socketLength);
if (ret < 0) {
perror("recvfrom() failed");
} else {
printf("# Receiving frame\n");
}
}
return EXIT_SUCCESS;
}