文章目录
1.前言
UDP组播测试对于局域网内数据链路测试十分必要,轻量化和易用性是首要考虑的问题,使用mping作为UDP组播测试工具,能够非常方便的进行linux、Windows等平台的组播测试。本文第4章还提供了基于C/C++的udp_sender和udp_reciver组播源码,可以在Linux下编译执行。
20240520更新,新建QT工程,本文第4节中的UDP-sender与reciver,已支持Windows+Linux跨平台编译,并支持GCC编译,源码与工程详见:
UDPWin+Linux跨平台测试工具源码工程
2.mping工具编译
GITHUB:https://github.com/tongxinCode/mping
或使用如下链接(go源码+build可执行程序)
CSDN:https://download.csdn.net/download/Axugo/89070577
官方给出的编译方法:
# windows
SET CGO_ENABLED=0
SET GOOS=windows
SET GOARCH=amd64
go build -o mping.exe main.go
# linux
SET CGO_ENABLED=0
SET GOOS=linux
SET GOARCH=amd64
go build -o mping main.go
# linux arm
SET CGO_ENABLED=0
SET GOOS=linux
SET GOARCH=arm
go build -o mping main.go
3.mping工具使用
以Windows为例,将编译好的mping.exe拷贝至C:\Windows\System32路径下,即可全局使用
3.1 参数说明
mping.exe -h
可以得到如下
mping version: mping/1.8.1
Usage: ./mping [-h] [-s sendGroup] [-r receiveGroup] [-l localAddress] [-S sourceAddress] [-m message] [-i interval] [-log path]
Options:
-C int
[number] the limit number of sending packets(-1 means no limits) (default -1)
-S string
[ip[:port]] must determine the peer source ip if using SSM (default "127.0.0.1:8888")
-c whether to count Packet loss rate(default false)
-e string
['ascii','utf8','gbk'] change the content of sending (default "ascii")
-h this help
-i int
[number] change the interval between package sent (unit:Nanosecond) (default 1000000000)
-l string
[ip[:port]] must choose your local using interface (default "127.0.0.1:8888")
-log string
[/tmp/] or [C:\] determine whether to log, Path e.g ./, Forbidden / (default "/")
-m string
[string] change the content of sending (default "Init Data")
-p int
[number] the size of payload data(0 means use 1472 Bytes payloads) (default -1)
-proto string
choose a lua script to parse udp data, function Parse(dataBytes) must be included (default "*.lua")
-r string
[group:port] receive packet from group (default "239.255.255.255:9999")
-s string
[group:port] send packet to group (default "239.255.255.255:9999")
-test
send and receive locally to examinate a test(default false)
-time
send real time as the content to examinate(default false)
-x whether to show the hex data(default false)
3.1 组播播发(-s)
将组播信息播发至本机的19901端口
mping.exe -s 127.0.0.1:19901
3.1 组播接收(-r)
从19901端口接收播发的组播信息
mping.exe -r 224.0.0.8:19901
3.3 Linux下mping测试
4.Linux组播udp_sender及udp_reciver使用
4.1 udp_sender源码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
//#define MULTICAST_GROUP "224.0.0.1"
//#define PORT 10000
int main(int argc,char *argv[]) {
if(argc<3)
{
printf("ERROR: argc<3 !\n");
printf("Example: ./udp_sender 224.0.0.8 18044 \n\n");
return 0;
}
int PORT=atoi(argv[2]);
char *MULTICAST_GROUP=argv[1];
struct sockaddr_in addr;
int sock;
char message[] = "This is a multicast test message...";
// 创建UDP套接字
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
// 设置组播TTL(生存时间)
int ttl = 1;
if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) {
perror("setsockopt failed");
exit(EXIT_FAILURE);
}
// 设置组播目标地址和端口
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(MULTICAST_GROUP);
addr.sin_port = htons(PORT);
while (1) {
// 发送消息
if (sendto(sock, message, strlen(message), 0, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("sendto failed");
exit(EXIT_FAILURE);
}
printf("udp_sender send msg to %s %d YES!\n\n",MULTICAST_GROUP,PORT);
sleep(1); // 每秒发送一次消息
}
// 关闭套接字
close(sock);
return 0;
}
4.1 udp_reciver源码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
//#define MULTICAST_GROUP "224.0.0.1"
//#define PORT 10000
#define MAX_BUFFER_SIZE 1024
//第一个参数:组播IP
//第二个参数:组播端口
int main(int argc,char *argv[]) {
if(argc<3)
{
printf("ERROR: argc<3 !\n");
printf("Example: ./udp_reciver 224.0.0.8 18044 \n\n");
return 0;
}
int PORT=atoi(argv[2]);
char *MULTICAST_GROUP=argv[1];
struct sockaddr_in addr;
int sock;
char buffer[MAX_BUFFER_SIZE];
ssize_t nbytes;
// 创建UDP套接字
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
// 设置套接字选项,允许多个进程绑定到相同的地址和端口
int reuse = 1;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) {
perror("setsockopt failed");
exit(EXIT_FAILURE);
}
// 绑定到特定地址和端口
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(PORT);
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
// 加入组播组
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(MULTICAST_GROUP);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0) {
perror("setsockopt failed");
exit(EXIT_FAILURE);
}
printf("wait receive multimessage...\n");
while (1) {
// 接收消息
nbytes = recvfrom(sock, buffer, sizeof(buffer), 0, NULL, 0);
if (nbytes < 0) {
perror("recvfrom failed");
exit(EXIT_FAILURE);
}
printf("Have receive multimessage from %s %d\n",MULTICAST_GROUP,PORT);
printf("%.*s\n", (int)nbytes, buffer);
}
// 关闭套接字
close(sock);
return 0;
}
4.3 编译方法
gcc sender.c -o udp_sender
gcc recver.c -o udp_reciver
4.4 测试使用
4.4.1 udp_sender
./udp_sender 224.0.0.8 19901
4.4.2 udp_reciver
./udp_reciver 224.0.0.8 19901
5.组播TTL参数说明
- TTL(Time To Live)是组播通信中的一个重要参数,用于控制数据包在网络中的传输范围和生命周期。TTL的作用是限制数据包在网络中传输的距离,防止数据包在网络中无限制地循环传输,从而导致网络拥塞和资源浪费。
- 在组播通信中,每个数据包都有一个TTL值,该值表示数据包在网络中可以经过的最大路由器数。当数据包经过一个路由器时,TTL值会减少1。当TTL值减少到0时,数据包会被丢弃,不再继续传输。这样可以保证数据包只在网络中传输一定的距离,避免了数据包在网络中无限制地传输。
- TTL的设置需要根据网络的拓扑结构和传输需求来确定。如果TTL值设置得太小,数据包可能无法到达目的地;如果TTL值设置得太大,数据包可能会在网络中循环传输,导致网络拥塞和资源浪费。因此,TTL的设置需要根据实际情况进行调整。
6.Linux下组播不通的调试方案
关闭防火墙:
systemctl stop firewalld.service
配置组播:
route add -net 224.0.0.0 netmask 224.0.0.0 dev lo
route add -net 224.0.0.0 netmask 224.0.0.0 dev eth0