簡體   English   中英

UDP組播套接字在Linux 64位平台上不起作用

[英]UDP Multicast socket doesn't work on a linux 64 bits platform

我寫了一個很小的C代碼來打開UDP多播套接字,它在32位平台上很好用,但是當我重新編譯代碼並在Linux 64位平台上嘗試時,它不起作用。 該程序在recvfrom()函數上無限期掛起。 我檢查了是否使用tcpdump在指定的網絡接口上實際收到了udp幀,但是一切正常。 有人對我的代碼有什么問題有想法嗎?

這是第一個代碼(在您發表評論之前):

#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。網絡接口是eth.40,位於66.46.40.100,但它可以在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;
}

代碼中存在一個明顯的64位問題,即recvfrom的最后一個參數應該是指向socklen_t的指針,而不是代碼中沒有unsigned int的指針。 socklen_t在64位機器上很可能是64位變量,而unsigned int很可能是32位。

另一個問題是socketDesc被取消簽名。 文件描述符總是經過簽名的,因此您實際上可以檢測到返回它們的函數中的錯誤。 您無法檢查所有功能中的錯誤,因此您的代碼可能更早失敗了,並且您沒有注意到。

另一個可能的問題是您的toLong函數,當您將其視為32位值時, long通常在64位平台上為64位。

嘗試使用警告進行構建,編譯器應該會很有幫助。 這絕對是編譯器會警告您的事情。 如果那沒有幫助,請仔細檢查手冊頁以了解您調用的所有函數,並檢查類型是否正確。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM