文章目录
- 1.前言
- 2.mping工具编译
- 3.mping工具使用
- 3.1 参数说明
- 3.1 组播播发(-s)
- 3.1 组播播发(-r)
- 3.3 Linux下mping测试
- 4.Linux组播udp_sender及udp_reciver使用
- 4.1 udp_sender源码
- 4.1 udp_reciver源码
- 4.3 编译方法
- 4.4 测试使用
- 4.4.1 udp_sender
- 4.4.2 udp_reciver
1.前言
UDP组播测试对于局域网内数据链路测试十分必要,轻量化和易用性是首要考虑的问题,使用mping作为UDP组播测试工具,能够非常方便的进行linux、Windows等平台的组播测试。本文第4章还提供了基于C/C++的udp_sender和udp_reciver组播源码,可以在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