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

如果目的地址是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 1024

struct 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无关。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值