SylixOS --- 链路层AF_PACKET套接字通信程序

链路层传输途径:
在这里插入图片描述
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

单趟延时数据如下:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_40390825/article/details/118379837
今日推荐