链路层传输途径:
server端代码:
/*********************************************************************************************************
**
** 中国软件开源组织
**
** 嵌入式实时操作系统
**
** SylixOS(TM)
**
** Copyright All Rights Reserved
**
**--------------文件信息--------------------------------------------------------------------------------
**
** 文 件 名: packet_test.c
**
** 创 建 人: Lu.Zhenping (卢振平)
**
** 文件创建日期: 2016 年 04 月 14 日
**
** 描 述: posix 兼容接口消息队列获得信息.
*********************************************************************************************************/
#define __SYLIXOS_EXTEND
#ifdef SYLIXOS
#include <gjbext.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/socket.h>
#include <net/if_ether.h>
#include <netpacket/packet.h>
#include <netinet/ip.h>
#include <net/if_arp.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <errno.h>
#include <sys/ioctl.h>
#define FPATS_END()
#define FPATS_PASS() 0
#define FPATS_FAIL() -1
#define FPATS_START()
#define FPATS_PRINT(fmt, arg...) printf(fmt, ##arg)
/*********************************************************************************************************
宏定义
*********************************************************************************************************/
#define TEST_BUF_SIZE (16 * 1024 * 1024) /* 16M */
#define FREAM_SIZE (2 * 1024)
#define BLOCK_SIZE getpagesize() /* 1 页 */
#define BUFSISE (2048)
#define IPV4_VERSION (0x4)
#define ETH_P_USER 0x0700
#define DATA_LEN 1489
#define DEBUG_EN (0)
/*********************************************************************************************************
用户自定义数据类型
*********************************************************************************************************/
struct my_p_hdr {
u_short type;
uint8_t num;
int len;
int dataoff;
} __attribute__((__packed__));
/*********************************************************************************************************
全局变量定义
*********************************************************************************************************/
static char *socktype = "raw";
static char *netif = "en1";
static char content[DATA_LEN + 14 + 11];
struct timespec tv_sec_begin;
struct timespec tv_sec_end;
float TDOA;
float tdoa;
/*********************************************************************************************************
** 函数名称: help
** 功能描述: 帮助信息
** 输 入 : NONE
** 返回 值: NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
void help (char *name)
{
printf("Usage: \n"
".%s <option1> <option2>.\n"
" <option1>: en1 ... \n"
" <option2>: raw/dgram \n"
" -h --help print this infomation.\n", name);
}
/*********************************************************************************************************
** 函数名称: args_parse
** 功能描述: 参数解析
** 输 入 : argc, argv[]
** 输 出 : 无
** 全局变量:
** 调用模块:
*********************************************************************************************************/
void args_parse (int argc, char *argv[])
{
int err = 0;
int idx = 0;
int c;
static struct option optionLong[] = {
{
"help", no_argument, NULL, 'h'},
{
NULL, 0, NULL, 0}
};
if (argc < 2) {
help(argv[0]);
exit(EXIT_FAILURE);
}
for (;;) {
c = getopt_long(argc, argv, "h", optionLong, &idx);
if (c == -1) {
netif = argv[1];
socktype = argv[2];
break;
}
switch (c) {
case 'h':
case '?':
err = 1;
break;
}
}
if (err) {
help(argv[0]);
exit(EXIT_SUCCESS);
}
}
/*********************************************************************************************************
** 函数名称: packet_mmap_server
** 功能描述: AF_PACKET 协议域的服务端程序 (mmap)
** 输 入 : argc : 参数个数
** argv : 参数列表
** 输 出 : ERROR
** 全局变量:
** 调用模块:
*********************************************************************************************************/
int main (int argc, char *argv[])
{
int sockfd;
int ret;
void *buff = NULL;
struct sockaddr_ll sockaddr;
struct ifreq ireq;
socklen_t socklen = sizeof(struct sockaddr_ll);
struct my_p_hdr *myhdr;
ssize_t recvlen, sendlen;
struct ethhdr *ethheader;
u_char tmpmac[ETH_ALEN];
if (argc > 2) {
memcpy(ireq.ifr_name, argv[1], 3);
} else {
memcpy(ireq.ifr_name, "en1", 3);
}
FPATS_START();
sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_USER));
if (sockfd < 0) {
perror("socket");
FPATS_END();
return (FPATS_FAIL());
}
ret = ioctl(sockfd, SIOCGIFINDEX, &ireq);
if (ret < 0) {
perror("ioctl");
goto exit2;
}
printf("ifindex : en%d\n", ireq.ifr_ifindex - 1);
bzero(&sockaddr, sizeof(sockaddr));
sockaddr.sll_family = AF_PACKET;
sockaddr.sll_protocol = htons(ETH_P_USER); /* 协议类型使用用户自定义 */
sockaddr.sll_ifindex = ireq.ifr_ifindex;
sockaddr.sll_hatype = ARPHRD_ETHER; /* 以太网硬件格式 */
sockaddr.sll_halen = ETH_ALEN;
sockaddr.sll_len = socklen;
ret = bind(sockfd, (struct sockaddr *)&sockaddr, socklen);
if (ret < 0) {
perror("bind");
goto exit2;
}
buff = content;
struct timespec settime;
struct timespec settime1;
recvlen = recvfrom(sockfd, (void *)buff, DATA_LEN + ETH_HLEN + 11,
0, (struct sockaddr *)&sockaddr, &socklen);
if (recvlen < 0) {
FPATS_PRINT("recvfrom recv data error.\n");
goto exit2;
}
// clock_gettime(CLOCK_REALTIME, &settime);
ethheader = (struct ethhdr *)buff;
memcpy(tmpmac, ethheader->h_dest, ETH_ALEN);
memcpy(ethheader->h_dest, ethheader->h_source, ETH_ALEN);
memcpy(ethheader->h_source, tmpmac, ETH_ALEN);
// clock_gettime(CLOCK_REALTIME, &settime1);
/*
* 再发回客户端
*/
sendlen = sendto(sockfd, (void *)buff, DATA_LEN + ETH_HLEN + 11,
0, (struct sockaddr *)&sockaddr, socklen);
if (sendlen < 0) {
FPATS_PRINT("sendto send fail.\n");
goto exit2;
}
// tv_sec_begin.tv_nsec = settime.tv_nsec;
// tv_sec_begin.tv_sec = settime.tv_sec;
// tv_sec_end.tv_nsec = settime1.tv_nsec;
// tv_sec_end.tv_sec = settime1.tv_sec;
//
// tdoa = (tv_sec_end.tv_sec * 1000000000 + tv_sec_end.tv_nsec) - (tv_sec_begin.tv_sec * 1000000000 + tv_sec_begin.tv_nsec);
// TDOA = (tdoa)/1000000000;
//
// printf("-------------------------------------------------------------single time is %f\n", TDOA);
myhdr = (struct my_p_hdr *)((char *)buff + ETH_HLEN);
/*
* 查看收到的数据包是否是客户端发送的
*/
if (ntohs(myhdr->type) == ETH_P_USER) {
printf("data: %s\n", (char *)(buff + ntohl(myhdr->dataoff)));
printf("[MYHDR] data len: %d\n", ntohl(myhdr->len));
printf("[MYHDR] data num: %d\n", myhdr->num);
printf("[MYHDR] type: %x\n", ntohs(myhdr->type));
printf("[MYHDR] data off: %d\n", ntohl(myhdr->dataoff));
}
close(sockfd);
FPATS_END();
return (FPATS_PASS());
exit2:
close(sockfd);
FPATS_END();
return (FPATS_FAIL());
}
/*********************************************************************************************************
END
*********************************************************************************************************/
client端程序:
/*********************************************************************************************************
**
** 中国软件开源组织
**
** 嵌入式实时操作系统
**
** SylixOS(TM)
**
** Copyright All Rights Reserved
**
**--------------文件信息--------------------------------------------------------------------------------
**
** 文 件 名: AF_PACKET_RAW_client.c
**
** 创 建 人: Lu.Zhenping (卢振平)
**
** 文件创建日期: 2016 年 04 月 14 日
**
** 描 述: AF_PACKET 测试
*********************************************************************************************************/
#define __SYLIXOS_EXTEND
#ifdef SYLIXOS
#include <gjbext.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <time.h>
#include <unistd.h>
#include <sys/socket.h>
#include <net/if_ether.h>
#include <netpacket/packet.h>
#include <network/lwip/prot/tcp.h>
#include <network/lwip/prot/udp.h>
#include <network/lwip/prot/dns.h>
#include <network/lwip/prot/etharp.h>
#include <network/lwip/prot/icmp.h>
#include <netinet/ip.h>
#include <netinet6/ip6.h>
#include <net/if_arp.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <sys/mman.h>
#include <netdb.h>
#include <poll.h>
#include <errno.h>
#include <sys/ioctl.h>
#define FPATS_END()
#define FPATS_PASS() 0
#define FPATS_FAIL() -1
#define FPATS_START()
#define FPATS_PRINT(fmt, arg...) printf(fmt, ##arg)
/*********************************************************************************************************
宏定义
*********************************************************************************************************/
#define TEST_BUF_SIZE (16 * 1024 * 1024) /* 16M */
#define FREAM_SIZE (2 * 1024)
#define BLOCK_SIZE getpagesize() /* 1 页 */
#define BUFSISE (2048)
#define IPV4_VERSION (0x4)
#define ETH_P_USER 0x0700
#define DATA_LEN 1489
#define DEBUG_EN (0)
/*********************************************************************************************************
用户自定义数据类型
*********************************************************************************************************/
struct my_p_hdr {
u_short type;
uint8_t num;
int len;
int dataoff;
} __attribute__((__packed__));
/*********************************************************************************************************
全局变量定义
*********************************************************************************************************/
static char content[DATA_LEN + 14 + 11];
static char recvbuf[DATA_LEN + 14 + 11];
static char *dst_mac;
struct timespec tv_sec_begin;
struct timespec tv_sec_end;
float TDOA;
float tdoa;
/*********************************************************************************************************
** 函数名称: help
** 功能描述: 帮助信息
** 输 入 : NONE
** 返回 值: NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
void help (char *name)
{
printf("Usage: \n"
".%s <option1> <parameter>.\n"
" -m [MAC-ADDR] --mac [MAC-ADDR eg. 00:11:22:33:44:55:66:77] \n"
" -h --help print this infomation.\n", name);
}
/*********************************************************************************************************
** 函数名称: args_parse
** 功能描述: 参数解析
** 输 入 : argc, argv[]
** 输 出 : 无
** 全局变量:
** 调用模块:
*********************************************************************************************************/
int args_parse (int argc, char *argv[])
{
int err = 0;
int idx = 0;
int c;
static struct option optionLong[] = {
{
"help", no_argument, NULL, 'h'},
{
"mac", required_argument, NULL, 'm'},
{
NULL, 0, NULL, 0}
};
if (argc < 2) {
help(argv[0]);
return (EXIT_FAILURE);
}
for (;;) {
c = getopt_long(argc, argv, "hm:", optionLong, &idx);
if (c == -1) {
break;
}
switch (c) {
case 'm':
dst_mac = optarg;
break;
case 'h':
case '?':
err = 1;
break;
}
}
if (err) {
help(argv[0]);
return (EXIT_FAILURE);
}
return (EXIT_SUCCESS);
}
/*********************************************************************************************************
** 函数名称: main
** 功能描述: AF_PACKET 协议域的客户端程序 (mmap)
** 输 入 : arg : 线程参数
** 输 出 : ERROR
** 全局变量:
** 调用模块:
*********************************************************************************************************/
int main (int argc, char *argv[])
{
int sockfd, ret;
char *buff = NULL;
struct ifreq ireq;
struct sockaddr_ll sockaddr;
struct ethhdr *ethheader;
struct my_p_hdr *myhdr;
int dstmac[ETH_ALEN];
int i;
ssize_t recvlen;
socklen_t socklen = sizeof(struct sockaddr_ll);
struct timespec settime;
if (args_parse(argc, argv) != EXIT_SUCCESS) {
return (-1);
}
FPATS_START();
sscanf(dst_mac, "%x:%x:%x:%x:%x:%x", &dstmac[0], &dstmac[1], &dstmac[2],
&dstmac[3], &dstmac[4], &dstmac[5]);
sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_USER));
if (sockfd < 0) {
perror("socket");
FPATS_PRINT("socket create fail.\n");
FPATS_END();
return (FPATS_FAIL());
}
memcpy(ireq.ifr_name, "en2", 3);
ret = ioctl(sockfd, SIOCGIFINDEX, &ireq);
if (ret < 0) {
perror("ioctl");
goto exit2;
}
// socklen = sizeof(struct sockaddr_ll);
printf("ifindex : en%d\n", ireq.ifr_ifindex - 1);
bzero(&sockaddr, sizeof(sockaddr));
sockaddr.sll_ifindex = ireq.ifr_ifindex;
sockaddr.sll_family = AF_PACKET;
sockaddr.sll_protocol = htons(ETH_P_USER);
sockaddr.sll_hatype = ARPHRD_ETHER;
sockaddr.sll_halen = ETH_ALEN;
sockaddr.sll_len = socklen;
buff = content;
ethheader = (struct ethhdr *)buff;
/*
* 填充目的 MAC 地址
*/
memcpy(ethheader->h_dest, dstmac, ETH_ALEN);
ret = ioctl(sockfd, SIOCGIFHWADDR, &ireq);
if (ret < 0) {
perror("ioctl");
goto exit2;
}
for (i = 0; i < ETH_ALEN; ++i) {
ethheader->h_source[i] = ireq.ifr_hwaddr.sa_data[i];
}
ethheader->h_proto = htons(ETH_P_USER);
myhdr = (struct my_p_hdr *)((char *)buff + sizeof(struct ethhdr));
myhdr->type = htons(ETH_P_USER);
myhdr->num = 10;
myhdr->len = htonl(DATA_LEN);
myhdr->dataoff = htonl(ETH_HLEN + sizeof(struct my_p_hdr));
for (i = 0; i < DATA_LEN; ++i) {
buff[i + ETH_HLEN + sizeof(struct my_p_hdr)] = 'a' + (i % 10);
}
clock_gettime(CLOCK_REALTIME, &settime);
ret = sendto(sockfd, buff, DATA_LEN + ETH_HLEN + sizeof(struct my_p_hdr), 0, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
tv_sec_begin.tv_nsec = settime.tv_nsec;
tv_sec_begin.tv_sec = settime.tv_sec;
if (ret < 0) {
perror("sendto");
goto exit2;
} else {
printf("data have sent\n");
recvlen = recvfrom(sockfd, (void *)recvbuf, DATA_LEN + ETH_HLEN + 11,
0, (struct sockaddr *)&sockaddr, &socklen);
clock_gettime(CLOCK_REALTIME, &settime);
tv_sec_end.tv_nsec = settime.tv_nsec;
tv_sec_end.tv_sec = settime.tv_sec;
tdoa = (tv_sec_end.tv_sec * 1000000000 + tv_sec_end.tv_nsec) - (tv_sec_begin.tv_sec * 1000000000 + tv_sec_begin.tv_nsec);
TDOA = (tdoa/2)/1000000000;
printf("-------------------------------------------------------------single time is %f\n", TDOA);
if (recvlen < 0) {
perror("recvfrom");
FPATS_PRINT("recvfrom recv data error.\n");
goto exit2;
}
/*
* 我自己发的数据?
*/
if (ntohs(myhdr->type) == ETH_P_USER && myhdr->num == 10) {
printf("[MYHDR] data len: %d\n", ntohl(myhdr->len));
printf("[MYHDR] data num: %d\n", myhdr->num);
printf("[MYHDR] type: %x\n", ntohs(myhdr->type));
printf("[MYHDR] data off: %d\n", ntohl(myhdr->dataoff));
int offset = ntohl(myhdr->dataoff);
for (i = 0; i < DATA_LEN; ++i) {
if (recvbuf[offset + i] != buff[offset + i]) {
FPATS_PRINT("af_packet recv data error.\n");
printf("recv data idx %d error, recv [%c] != send [%c]",
i, recvbuf[offset + i], buff[offset + i]);
}
}
} else {
/*
* 不是我发的数据, 有问题?
*/
goto exit2;
}
}
close(sockfd);
FPATS_END();
return (FPATS_PASS());
exit2:
close(sockfd);
FPATS_END();
return (FPATS_FAIL());
}
/*********************************************************************************************************
END
*********************************************************************************************************/
执行操作:
服务端执行指令,默认en1网卡:
./AF_PACKET_RAW_server en1
客户端执行指令,MAC地址为服务端网卡MAC地址:
./AF_PACKET_RAW_client -m 00:00:00:00:00:00
单趟延时数据如下: