UDP 组播 广播 客户端 服务端 (linux C)
组播网络调试过程中碰见的问题
1.在虚拟机和windows之间组播或是广播通信的时候,如果接收端或者发送端是windows,需要绑定到虚拟网卡的IP地址,绑定代码需要用到参数 IP_MULTICAST_IF
//以下两行是指定网卡发送数据包
unsigned long addr = inet_addr("192.168.206.137");
// IP_MULTICAST_IF 该参数设置组播的网络接口,会从给定的网络接口发送,另一个网络接口会忽略此数据
// INADDR_ANY 是选定默认的网络接口,一般由系统内部自行进行选择,一般会选择 路由表 绑定一个明确的地址
setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF, (char *)&addr, sizeof(addr));
2.在python接收组播代码中有绑定到网卡的代码示例,如下文 python 接收组播示例
udp 广播, 服务端, 一直发送数据
适用单网卡,多网卡需要自行绑定网卡
int scoket_id = -1;
scoket_id = socket(AF_INET, SOCK_DGRAM, 0);
if(scoket_id < 1) {
printf("-error- create socket failed %d\n", scoket_id);
exit(errno);
}
struct sockaddr_in server_c, client_c;
int slen = sizeof(server_c);
int clen = sizeof(client_c);
server_c.sin_family = AF_INET;
server_c.sin_addr.s_addr = htonl(INADDR_ANY);
server_c.sin_port = htons(4444);
if(bind(scoket_id,(struct sockaddr*)&server_c, slen) < 0) {
perror("-error- bind error");
exit(errno);
}
client_c.sin_family = AF_INET;
client_c.sin_port = htons(1111);
inet_pton(AF_INET,"192.168.100.255",&client_c.sin_addr.s_addr);
// 注意 广播的范围地址, 同网段下的 255
/*
* 设置广播属性,打开服务器广播权限
*/
if (setsockopt(scoket_id, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
fprintf(stderr, "initSvr: Socket options set error.\n");
exit(errno);
}
printf("-----------> 1\n");
unsigned char buff[10] = {'1','2','3','4','5','6','7','8','8','0'};
while (1)
{
int rlen = sendto(scoket_id, buff, 10, 0, (struct sockaddr*)&client_c, clen);
printf("-send data- %d \n", rlen);
sleep(1);
}
udp 组播, 一直接收数据
适用单网卡,多网卡需要自行绑定网卡
int scoket_id = -1;
scoket_id = socket(AF_INET, SOCK_DGRAM, 0);
if(scoket_id < 1) {
printf("-error- create socket failed %d\n", scoket_id);
exit(errno);
}
pnode_tmp->node_info.socket_c = scoket_id;
pnode_tmp->send_fail_n = 0;
struct sockaddr_in server_c;
struct ip_mreq mreq;
int slen = sizeof(server_c);
int clen = sizeof(mreq);
server_c.sin_family = AF_INET;
server_c.sin_addr.s_addr = htonl(INADDR_ANY);
server_c.sin_port = htons(4444);
if(bind(scoket_id,(struct sockaddr*)&server_c, slen) < 0) {
perror("-error- bind error");
exit(errno);
}
/*加入多播组*/
mreq.imr_interface.s_addr = inet_addr("192.168.100.100");
mreq.imr_multiaddr.s_addr = inet_addr("232.0.0.10");
if (setsockopt(scoket_id, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
{
perror("setsockopt");
return -1;
}
printf("-----------> 1\n");
unsigned char buff[10] = {'1','2','3','4','5','6','7','8','8','0'};
while (1)
{
int rlen = recvfrom(sockfd, buff, 10, 0, (struct sockaddr *)&server_c, &slen);
printf("-recv data- %d \n", rlen);
sleep(1);
}
udp 组播, 一直发送数据
适用单网卡,多网卡需要自行绑定网卡
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main(int argc, char **argv)
{
struct sockaddr_in peeraddr;
int sockfd;
unsigned int socklen;
/* 创建 socket 用于UDP通讯 */
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("socket\n");
exit(errno);
}
printf("socket created success!!!\n");
socklen = sizeof(struct sockaddr_in);
/* 设置对方的端口和IP信息 */
memset(&peeraddr, 0, socklen);
peeraddr.sin_family = AF_INET;
peeraddr.sin_port = htons(4444);
if (inet_pton(AF_INET, "224.0.0.10", &peeraddr.sin_addr) <= 0) {
printf("wrong group address!\n");
exit(0);
}
/* 循环接受用户输入的消息发送组播消息 */
unsigned char buff[10] = {'1','2','3','4','5','6','7','8','8','0'};
while(1) {
if (sendto(sockfd, buff, 10, 0, (struct sockaddr *)&peeraddr, sizeof(struct sockaddr_in)) < 0) {
printf("sendto error!\n");
exit(errno);
}
printf("client sendto success!\n");
sleep(1);
}
return 0;
}
python 接收组播数据
适用多网卡,已经设置了指定IP(192.168.206.1)的网口
import threading, socket, select, traceback, sys, struct, re, random
from time import sleep
isclose = 0
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) #创建一个套接字
udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
udp_socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255)
udp_socket.setsockopt(
socket.IPPROTO_IP,
socket.IP_ADD_MEMBERSHIP,
socket.inet_aton("232.0.0.1") + #指定组播号
socket.inet_aton("192.168.206.1") #指定网卡,如果是虚拟机,需要绑定到指定虚拟机的端口号
)
udp_socket.bind(('0.0.0.0', 4444)) #绑定本地信息,自己电脑的ip和程序的端口。ip一般不用写,表示本机的任意一个ip,端口大于常用的1023就可以
while True:
try:
infds, outfds, errfds = select.select([udp_socket,], [], [], 5)
if len(infds) > 0:
udp_data = udp_socket.recvfrom(1024) #接收数据,1024表示本次接收的最大字节数
print(udp_data)
if len(udp_data[0]) == 21:
fmt = '!HBffffH'
#c8 c9 01 41 58 a3 d7 41 58 a3 d7 41 58 a3 d7 41 58 a3 d7 00 15
rbuf = struct.unpack(fmt, udp_data[0])
if rbuf[0] == 0xc8c9:
print(rbuf)
arg1 = round(rbuf[2], 2)
arg2 = round(rbuf[3], 2)
arg3 = round(rbuf[4], 2)
arg4 = round(rbuf[5], 2)
else:
print("数据格式不正确...")
else:
print("正常连接...")
if isclose != 0:
udp_socket.shutdown(socket.SHUT_RDWR)
break
except Exception as ex:
traceback.print_exc()
print(ex)
break;
本文来自博客园踩坑狭,作者:韩若明瞳,转载请注明原文链接:https://www.cnblogs.com/han-guang-xue/p/16405741.html