如何让多播报文从指定的网口发出去

来源:互联网 发布:单片机属于嵌入式吗 编辑:程序博客网 时间:2024/05/14 21:35

如果目的地址是multicast, 可以使用 socket 选项 IP_MULTICAST_IF,它指定多播报文是哪个网络接口发出去:

    struct Ip_in_addr in_addr; /* for IP_IP_MULTICAST_IF */    struct sockaddr_in myAddr;  /* for bind */    /* create client's socket */    if((sFd = socket(AF_INET, SOCK_DGRAM,0)) == ERROR ) {        perror ("socket");        return (ERROR);    }    /* test IP_IP_MULTICAST_IF */    in_addr.s_addr = inet_addr(nic); /* interface address */    if (ipcom_setsockopt(sFd, IP_IPPROTO_IP, IP_IP_MULTICAST_IF, &in_addr, sizeof(in_addr)) < 0) {        printf ("ipcom_setsockopt IP_IP_MULTICAST_IF failed, errno = %d\n", errno);    }

这是我写的一个udp client 程序,在vxworks 下通过。 修改一下头文件,应该也可以在其它操作系统下编译和运行。

/* test if udp broadcast is OK *//* Dai Yuwen, December 2011 */#include <vxWorks.h>#include <sockLib.h>#include <inetLib.h>#include <hostLib.h>#include <string.h>#include <stdio.h>#include <ipcom_sock.h>#define SERVER_PORT_NUM 9#define REQUEST_MSG_SIZE 1024struct request {    int display;    char message[REQUEST_MSG_SIZE];};/* usage: udpClient serverIP, interfaceIP */STATUS udpClient(char *serverName, char* nic){    struct request myRequest;    struct sockaddr_in serverAddr;    int sockAddrSize;     int sFd;    int mlen;    int addr;    struct Ip_in_addr in_addr; /* for IP_IP_MULTICAST_IF */    struct sockaddr_in myAddr;  /* for bind */    /* create client's socket */    if((sFd = socket(AF_INET, SOCK_DGRAM,0)) == ERROR ) {        perror ("socket");        return (ERROR);    }    /* test IP_IP_MULTICAST_IF */    in_addr.s_addr = inet_addr(nic); /* interface address */    if (ipcom_setsockopt(sFd, IP_IPPROTO_IP, IP_IP_MULTICAST_IF, &in_addr, sizeof(in_addr)) < 0) {        printf ("ipcom_setsockopt IP_IP_MULTICAST_IF failed, errno = %d\n", errno);    }    /* bind not required - port is dynamic */#if 1    bzero(&myAddr, sizeof(myAddr));    myAddr.sin_family = AF_INET;    myAddr.sin_addr.s_addr = inet_addr(nic);  /* interface address */    /*myAddr.sin_addr.s_addr = htonl(INADDR_ANY);  /* interface address */    myAddr.sin_port = 0; /* let kernel choose port */    if(bind(sFd, (struct sockaddr *)&myAddr, sizeof(myAddr)) < 0) {        printf ("bind failed, errno = %d s_addr = %x\n", errno, myAddr.sin_addr.s_addr);    }#endif      /* bind server socket address */    sockAddrSize = sizeof(struct sockaddr_in);    bzero((char*)&serverAddr, sockAddrSize);    serverAddr.sin_family = AF_INET;    serverAddr.sin_port = htons(SERVER_PORT_NUM);#if 0       if(((serverAddr.sin_addr.s_addr = inet_addr(serverName)) == ERROR )&&               ((serverAddr.sin_addr.s_addr = hostGetByName(serverName)) == ERROR)) {        perror ("unknown server name");        close(sFd);        return (ERROR);    }    serverAddr.sin_addr.s_addr = hostGetByName(serverName);    if (serverAddr.sin_addr.s_addr == ERROR){        perror ("unknown server name");        close(sFd);        return (ERROR);    }#endif    addr = inet_addr(serverName);    if (serverAddr.sin_addr.s_addr == ERROR){        perror ("unknown server name");        close(sFd);        return (ERROR);    }    serverAddr.sin_addr.s_addr = addr;    memcpy (myRequest.message, "greeting from vxworks", 21);    if(sendto(sFd, (caddr_t)&myRequest, 0 /*sizeof(myRequest)*/, 0,                (struct sockaddr *)&serverAddr, sockAddrSize) == ERROR) {        perror ("sendto");        close(sFd);        return(ERROR);    }    close(sFd);    return(OK);}

用法是这样的:

-> udpClient "224.0.0.1","192.168.20.1"  -> udpClient "224.0.0.1","172.25.52.31"

udpClient 的第二个参数指定的是网口地址,表示要从该网口出去。 在PC上抓
包,验证了这点。

另外,我还验证了调用bind是没有用的,虽然源IP地址按要求设置了, 但UDP包并不从
指定IP地址的那个口出去,这是符合预期的,因为到底从哪个口出去,由路由决
定,而查找路由是根据目的IP地址,跟源IP无关。

还有,有人想把广播包从指定网口发出去,用这个选项是没有用的。 只能加路由解决。

原创粉丝点击