linux 组播接收和发送代码和组播问题总结

linux 组播接收和发送代码和组播问题总结


int main(int argc, char *argv[])

{

int sockfd;
struct sockaddr_in localSock;
struct sockaddr_in addr;

struct ip_mreq group;
int datalen;
char databuf[4000];
int reuse;
struct timeval tv;
int maxfd;
fd_set readfds;
int retval;
int loopBack = 1;

printf("devdis start\n");


sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sockfd <= 0x0)
{
printf("create sockfd failed\n");
return -1;
}


/*端口释放后立即就可以被再次使用*/
reuse = 0x1;
if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0)
{
printf("Setting SO_REUSEADDR failed\n");
return -1;
}


memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(12345);
    addr.sin_addr.s_addr = inet_addr("224.1.1.1");

memset(&localSock, 0, sizeof(localSock));
localSock.sin_family = AF_INET;
    localSock.sin_port = htons(12345);
    localSock.sin_addr.s_addr = INADDR_ANY;


if(bind(sockfd, (struct sockaddr*)&localSock, sizeof(localSock)) != 0x0)
{
printf("bind failed\n");
return -1;
}


/*设置是否支持本地回环接收*/

loopBack = 0;
if(setsockopt(sockfd, IPPROTO_IP,  IP_MULTICAST_LOOP, &loopBack, sizeof(loopBack));
{
printf("set IP_MULTICAST_LOOP failed\n");
return -1;
}

memset(&group, 0, sizeof(group));
group.imr_multiaddr.s_addr = inet_addr("224.1.1.1");

group.imr_interface.s_addr =INADDR_ANY;

    if(setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group)) < 0)
//if(setsockopt(sockfd, IPPROTO_IP, 12, (char *)&group, sizeof(group)) < 0)
    {
    printf("adding multicast group failed\n");
return -1;
    }


maxfd = sockfd;
while(1)
{
FD_ZERO(&readfds);
FD_SET(sockfd, &readfds);
tv.tv_sec = 1;
tv.tv_usec = 0;
retval = select(maxfd + 1, &readfds, NULL, NULL, &tv);
if(retval < 0x0)
{
printf("select err\n");
}
else if(retval == 0x0)
{
continue;
}
else
{
if(FD_ISSET(sockfd, &readfds))
{
memset(databuf, 0, 4000);
datalen = read(sockfd, databuf, 4000);
printf("datalen = %d\n", datalen);
printf("%s\n",databuf);
sendto(sockfd, "12345", 5, 0, (struct sockaddr*)&addr, sizeof(struct sockaddr_in));
}
}
}
return 0;
}

1、由于socket 版本不一样,IP_ADD_MEMBERSHIP 宏定义的值不同,在v1 中定义值为5 在v2中定义值为12,如果编译器版

与内核版本不同,则可能出现加入组播组失败。


2、如果设备不添加默认路由,也可能出现加入组播组时(IP_ADD_MEMBERSHIP)返回-1错误。特imr_interfac INADDR_ANY时。如果imr_interfac = 本地IP地址时不会出现。


3、多网卡设备上发送组播消息,需要指明确指定为要发送组播数据包的网卡IP地址,而不可以使用INADDR_ANY设置;如果使用

INADDR_ANY,则系统会默认根据路由表绑定一个明确的地址,则在接收组播信息时,无法从发送的网卡处接收到数据,发送的网卡没有被添加到组播中,必须使用setsockopt设置IP_MULTICAST_IF选项,从而修改默认的组播出口网卡。否则系统根据路由表发送到默认网关。而不一定是指定的网卡。

4、在多网卡实现多播(如设备搜索)相关的功能时,可以针对多个网卡分别执行一次操作,同时可以区分设备是从哪个网卡搜索到的。

5、主机必须成为一个或多个 IP 多播组的成员,才能接收 IP 多播stru数据报。进程可以使用以下套接字选项请求主机加入多播组:

struct ip_mreq mreq;
setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq))

其中 mreq 为以下结构:
struct ip_mreq {
    struct in_addr imr_multiaddr;   /* multicast group to join */
    struct in_addr imr_interface;   /* interface to join on */
}
每个成员关系都与单个接口关联。可以在多个接口上加入同一组。将 imr_interface 地址指定为 INADDR_ANY 以选择缺省的多播接口。还可以通过指定主机的本地地址之一来选择特定的具有多播功能的接口。


6、IP_MULTICAST_IF:

即使主机拥有多个具有多播功能的接口,每个多播传输也是通过单个网络接口发送的。如果主机还用作多播路由器且 TTL 值大于 1,则多播可以转发到源接口之外的接口。可以使用套接字选项覆盖来自给定套接字的后续传输的缺省设置:

struct in_addr addr;
setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &addr, sizeof(addr))

其中 addr 是所需传出接口的本地 IP 地址。通过指定地址 INADDR_ANY 恢复到缺省接口。使用 SIOCGIFCONF ioctl 获取接口的本地 IP 地址。要确定接口是否支持多播,请使用 SIOCGIFFLAGS ioctl 获取接口标志并测试是否设置了 IFF_MULTICAST 标志。此选项主要用于多播路由器以及其他专门针对 Internet 拓扑的系统服务。

7、IP_MULTICAST_LOOP

如果将多播数据报发送到发送主机本身所属的组,则缺省情况下,本地传送的 IP 层将回送此数据报的副本。另一套接字选项可为发送主机提供针对是否回送后续数据报的显式控制:

u_char loop;
setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop))

其中 loop 为 0 即为禁用回送,为 1 即为启用回送。此选项通过消除因接收应用程序自己的传输内容而产生的开销,可提高单台主机上只有一个实例的应用程序的性能。对于可以在一台主机上具有多个实例或者其发送主机不属于目标组的应用程序,不应使用此选项。

如果发送主机属于其他接口的目标组,则发送初始 TTL 值大于 1 的多播数据报可以传送到其他接口上的发送主机。回送控制选项不会影响此类传送。






  • 4
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux上使用SocketCAN可以很方便地进行CAN数据的接收发送。以下是一个简单的例子: ``` #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <net/if.h> #include <linux/can.h> #include <linux/can/raw.h> int main(int argc, char **argv) { int s; struct sockaddr_can addr; struct can_frame frame; struct ifreq ifr; const char *ifname = "can0"; // CAN接口名称 // 创建socketCAN套接字 s = socket(PF_CAN, SOCK_RAW, CAN_RAW); if (s < 0) { perror("socket"); return 1; } // 设置CAN接口名称 strcpy(ifr.ifr_name, ifname); ioctl(s, SIOCGIFINDEX, &ifr); // 绑定CAN接口 addr.can_family = AF_CAN; addr.can_ifindex = ifr.ifr_ifindex; bind(s, (struct sockaddr *)&addr, sizeof(addr)); // 接收CAN帧 while (1) { int nbytes = read(s, &frame, sizeof(frame)); if (nbytes < 0) { perror("read"); return 1; } printf("Received CAN frame: id=0x%x, data=%02x %02x %02x %02x %02x %02x %02x %02x\n", frame.can_id, frame.data[0], frame.data[1], frame.data[2], frame.data[3], frame.data[4], frame.data[5], frame.data[6], frame.data[7]); } // 发送CAN帧 memset(&frame, 0, sizeof(frame)); frame.can_id = 0x123; frame.can_dlc = 8; strcpy(frame.data, "HelloCAN"); write(s, &frame, sizeof(frame)); close(s); return 0; } ``` 上述代码使用了SocketCAN的API,首先创建了一个socketCAN套接字,然后绑定了CAN接口。接着,使用read函数接收CAN帧,使用write函数发送CAN帧。可以根据实际需求修改CAN帧的ID、数据等内容。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值