精华内容
下载资源
问答
  • 前面几部分着重描述UART通信方式及其特点的一些概念介绍与理解。 、文档导航 1、什么是串行通信 2、什么是并行通信 3、什么是同步通信 4、什么是异步通信 5、全双工、半双工、单工三者区别  6、标

    文档简介:本文档主要讲解了关于STM32F103C8T6 外设之UART数据上传与下发的功能实现以及UART的基本概念。这里对于寄存器的配置不做分析,提供UART标准程序的设计思路。前面几部分着重描述UART通信方式及其特点的一些概念介绍与理解。

    一、文档导航

    1、什么是串行通信

    2、什么是并行通信

    3、什么是同步通信

    4、什么是异步通信

    5、全双工、半双工、单工三者区别

      6、标准UART的通信数据帧格式

    7、标准UART程序设计思路

    8、STM32F103C8T6 UART内部框架

    9、具体实现代码

      10、后续更新

    二、什么是串行通信

    2.1 概念理解

    只有一根数据线的通信方式叫串行通信。就是将数据一个一个位传递,实现串行通信。

    2.2 此通信方式特点

            优点:硬件设计非常简单,可靠性高。

    缺点:数据传输速度慢,不适合需求数据传输速度快的设备。

    三、什么是并行通信

    3.1 概念理解
    具有多条线的进行数据通信的方式叫并行通信。

    3.2 此通信方式特点

      优点:通信速度快。适合需求数据传输速度的设备。

    缺点:硬件设计复杂,可靠性低。

    四、什么是同步通信

    4.1  概念

    通信双方具有相同的时钟,并且有时钟线相连接。

      4.2 通讯特点

    通信数据会持续输出,不会存在积累误差。

    五、什么是异步通信

    5.1 概念

      通信双方不具有相同的时钟,没有时钟线相连接。

    5.2 通讯特点

    通信双方数据输出会存在积累误差。为了解决积累误差,数据不准确的问题,采用数据没传输一帧,下一次数据传输就从帧头开始传输。

    六、全双工、半双工、单工三者区别

    6.1 全双工

    在同一时刻,数据的收发能够同时进行,互不干扰。其数据线为双向单线。

      6.2 单双工

    在同一时刻,数据收发只能进行收或者发,相当于独木桥。要么收,要么发,正在进行数据交换时,可以对数据收发的方向进行切换。其数据线为双线单线。

    6.3 单工

    只具有一个方向的数据通信。具有单向性。其数据线为单向单线。

    6.4 UART属于全双工。

    七、标准UART的通信数据帧格式

    7.1 通信方式

    标准UART属于异步串行通信,也是全双工通信。

    7.2 帧格式说明

    在UART的通信方式中,它的数据或者字符是以帧格式进行数据传送的。帧格式为串口通信的数据格式。其帧格式是以一个起始位“0”表示字符的开始,接着是5-8位的数据位,一般规定低位在前,高位在后;数据位后是奇偶校验位,然后是停止位。停止位一般分为0.5位、1位、1.5位、2.0位。一个完整的帧格式从起始位到停止位。

    起始位:通信线上没有数据传送时,为高电平(逻辑1);当要发送数据时,首先发1个低电平信号(逻辑0),此信号称为“起始位”,表示开始传输1帧数据。

    数据位:起始位之后就是数据位,数据位一般为5-8位,规定低位在前、高位在后。一般都是从低位开始传送,然后高位传送。

    奇偶校验位:数据位之后的位为奇偶校验位(有的方式具有)。此位可用于判别字符传送的正确性,其有3种可能的选择,即奇、偶、无校验,用户可根据需要选择

    停止位:它是一个字符数据的结束标志。可以是1位、1.5位(每一位时间是固定,1.5位就是高电平时间 长度是1.5位占用的时间)、2位的高电平。 由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。

    八、标准UART程序设计思路

    8.1 实现UART通信的必备四大元素

            波特率:一秒钟传输的二进制位数。

    数据位:实际数据一般存放在数据位。5-8位。

    停止位:主要用来消除积累误差

    校验位:硬件校验,一般的硬件支持奇偶校验。

    8.2 UART通信

    常规的UART通信,只需要实现以下几个方面即可通信。

            ①配置UART通信的四大元素--UART初始化;

    ②数据发送函数

            ③数据接收函数

    九、STM32F103C8T6 UART内部框架

    9.1内部框架

    如果通过配置寄存器的方式,需要对UART内部框架图进行详细分析。

    9.2具体配置过程

    9.2.1 UART初始化

    ①开启TX/RX对应IO时钟、开启串口时钟、IO引脚复用时钟

    ②TX配置成复用推挽输出、RX配置成上下拉输入

    ③TX/RX复用为串口使能

    ④计算波特率、写入波特率寄存器

    ⑤使能UART、配置数据格式(1-start、8-databit、1-stop)、奇偶校验位、停止位

    ⑥发送使能、接收使能

    ⑦若需中断,开启UART总中断,开启接收空闲中断,NVIC控制器配置。

            ⑧中断服务处理

            9.2.2 数据发送

    等待发送完成、将发送的data写入register;

    9.2.3 数据接收

    等待接收完成,将register的值传递到buff;

    十、具体实现代码

    #include "uart.h"
    #include <stdio.h>
    #include <rt_misc.h>

    volatile uint8_t uart_interrupt_flag = UART_RECE_DATA_NO_FLAG;
    char uart_frame_buffer[UART_RECE_LENGTH];
    #if 1  
    #pragma import(__use_no_semihosting_swi)

    struct __FILE
    {
        int handle; 
    };

    FILE __stdout;       
    int fputc(int ch, FILE *f)
    {
        return ( send_data(ch));
    }

    int ferror(FILE *f)
    {
        /* Your implementation of ferror */
        return EOF;
    }

    void _ttywrch(int ch)
    {
        send_data(ch);
    }

    void _sys_exit(int return_code)
    {
    label:
        goto label;  /* endless loop */
    }
    #endif

    #if UART_INTERRUPT

    void uart_interrupt_init(void)
    {
    uint32_t Priority;
    USART1->CR1 |= 1 << 5;
    USART1->CR1 |= 1 << 4;
    NVIC_SetPriorityGrouping(7-2);
    Priority=NVIC_EncodePriority(7-2,3,1);
    NVIC_SetPriority(USART1_IRQn,Priority);
    NVIC_EnableIRQ(USART1_IRQn);          
    }

    #endif

    void uart1_init(uint32_t baund,uint32_t clk)
    {
    float temp;
    uint16_t mantissa;
    uint16_t fraction;

    RCC->APB2ENR |= 1 << 2;
    RCC->APB2ENR |= 1 << 14;

    RCC->APB2ENR |= 1 << 0; 
    GPIOA->CRH &= ~(0xFF << 4);
    GPIOA->CRH |=  (0x4B << 4);

    AFIO->MAPR2 &= ~(0X1 << 2);

    temp =  (float)(clk)/ (baund * 16.0);
    mantissa = temp ;                    
    fraction =(int)(temp -mantissa)*16 + 0.5f;

    mantissa <<= 4;
    mantissa |= fraction;
    USART1->BRR = mantissa;

    USART1->CR1 |= 1 << 13 |  
                  0 << 12 |  
      0 << 10 |  
      0 << 8  |  
      1 << 2  |   //receiver enable
      1 << 3  ;   //transform enable
    USART1->CR2 |= (0 << 12);
    USART1->CR2 |= (0 << 13);

    USART1->CR3 = 0;
    #if UART_INTERRUPT
    uart_interrupt_init();
    #endif
    }

    char send_data(char buff)
    {
    while(!( (USART1->SR) & (1 << 7)  ))
    {
    ;
    }
    USART1->DR = buff;
    return buff;
    }

    char rece_data(void)
    {
    while(!( (USART1->SR) & (1 << 5)))
    {
    ;
    }
    return USART1->DR;
    }

    void send_data_string(char *string)
    {
    while(*string)
    {
    send_data(*string++);
    }
    send_data('\r');
    send_data('\n');
    }

    char* rece_data_string(char *string)
    {
    uint8_t r_data;
    uint8_t i=0;
    while(1)
    {
    r_data = rece_data();
    string[i++]=r_data;
    if(r_data == '\n')
    {
    break;
    }
    #if 1
    #if (ECHO == ECHO_ON)


    send_data(r_data) ;
    #endif
    #endif      
        }
    #if 1
    #if (ECHO == ECHO_ON)
    send_data('\r') ;
    send_data('\n') ;
    #endif
    #endif
    string[i]=0;
    return string;
    }

    void USART1_IRQHandler(void)
    {

    uint32_t ch_data;
        static uint32_t i=0;

    if( (USART1->SR)  & (1 << 5))
    {
    ch_data=USART1->DR;
    uart_frame_buffer[i++]=ch_data;
    if(i >= UART_RECE_LENGTH)
    {
    uart_frame_buffer[i++]='\0';
    uart_interrupt_flag = UART_RECE_DATA_NO_FLAG;//Òç³ö±êÖ¾
    i=0;
    }
    }
    if( (USART1->SR) & (1 << 4))
    {
    ch_data=USART1->DR;
    uart_frame_buffer[i++]='\0';
    i=0;
    uart_interrupt_flag = UART_RECE_DATA_OK_FLAG;
    }
    }

    在实现过程中,波特率配置出现问题,写入寄存器没有注意到小数部分为前面四位,刚开始理解成前面8位,导致串口上传failed;

    另外还有volatile 此关键词在应用,不管在哪里都需要将它放在变量前。

    十一、后续更新会继续更新 大笑


    展开全文
  • 内核与用户空间通信有很多种通信方式,netlink是其中种,其余的还有/proc、ioctl、sockopt、共享内存等等。netlink的特点异步全双工。 netlink使用32位端口寻址,称为pid(与进程号没有关系),其中内核的pid...

    内核与用户空间通信有很多种通信方式,netlink是其中一种,其余的还有/proc、ioctl、sockopt、共享内存等等。netlink的特点是异步全双工。

     

    netlink使用32位端口寻址,称为pid(与进程号没有关系),其中内核的pid地址为0,。netlink主要特性如下:

     

    1 支持全双工、异步通信(当然同步也支持)

    2 用户空间可使用标准的BSD socket接口(但netlink并没有屏蔽掉协议包的构造与解析过程,推荐使用libnl等第三方库)

    3 在内核空间使用专用的内核API接口

    4 支持多播(因此支持“总线”式通信,可实现消息订阅)

    5 在内核端可用于进程上下文与中断上下文

    转载于:https://www.cnblogs.com/chjgongzuo/p/8638742.html

    展开全文
  • 内核与用户空间通信有很多种通信方式,netlink是其中种,其余的还有/proc、ioctl、sockopt、共享内存等等。netlink的特点异步全双工。 netlink使用32位端口寻址,称为pid(与进程号没有关系),其中内核的pid...

     

     

    (本章基于:Linux-4.4.0-37)

    内核与用户空间通信有很多种通信方式,netlink是其中一种,其余的还有/proc、ioctl、sockopt、共享内存等等。netlink的特点是异步全双工。

    netlink使用32位端口寻址,称为pid(与进程号没有关系),其中内核的pid地址为0,。netlink主要特性如下:


    1 支持全双工、异步通信(当然同步也支持)

    2 用户空间可使用标准的BSD socket接口(但netlink并没有屏蔽掉协议包的构造与解析过程,推荐使用libnl等第三方库)

    3 在内核空间使用专用的内核API接口

    4 支持多播(因此支持“总线”式通信,可实现消息订阅)

    5 在内核端可用于进程上下文与中断上下文


    基本数据结构


    struct msghdr {
        void         *msg_name;       /* optional address */
        socklen_t     msg_namelen;    /* size of address */
        struct iovec *msg_iov;        /* scatter/gather array */
        size_t        msg_iovlen;     /* # elements in msg_iov */
        void         *msg_control;    /* ancillary data, see below */
        size_t        msg_controllen; /* ancillary data buffer len */
        int           msg_flags;      /* flags (unused) */
    };
     
    struct sockaddr_nl
    {
        sa_family_t nl_family; /*该字段总是为AF_NETLINK */
        unsigned short nl_pad; /* 目前未用到,填充为0*/
        __u32 nl_pid; /* process pid */
        __u32 nl_groups; /* multicast groups mask */
    };
     
     
    struct sockaddr_nl是netlink通信地址,和我们通常socket编程中的sockaddr_in作用一样。pid表示通信端口,groups表示组,注意这里为希望加入多播组号的掩码,也就是说最多只支持32个组。
    struct nlmsghdr
    {
        __u32 nlmsg_len; /* Length of message including header */
        __u16 nlmsg_type; /* Message content */
        __u16 nlmsg_flags; /* Additional flags */
        __u32 nlmsg_seq; /* Sequence number */
        __u32 nlmsg_pid; /* Sending process PID */
    };
    Netlink报文的数据区由消息头和消息体构成,struct nlmsghdr即为消息头,消息体接在消息头后。


    内核层操作

    创建socket


    static inline struct sock *
    netlink_kernel_create(struct net *net, int unit, struct netlink_kernel_cfg *cfg);
    net:  一般直接填&init_net
    unit:协议类型,可自定义,如#define NETLINK_TEST 25

    cfg:配置结构,类型如下:


    /* optional Netlink kernel configuration parameters */
    struct netlink_kernel_cfg {
        unsigned int    groups;
        unsigned int    flags;
        void        (*input)(struct sk_buff *skb);
        struct mutex    *cb_mutex;
        int        (*bind)(struct net *net, int group);
        void        (*unbind)(struct net *net, int group);
        bool        (*compare)(struct net *net, struct sock *sk);
    };

    groups:组编号;
    input:接收回调函数,接收一个sk_buff结构,数据包含一个nlmsghdr协议头;

    return:返回一个sock结构,返回NULL表示创建失败;

    单播发送接口:


    extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 portid, int nonblock);
    (1) ssk:为函数 netlink_kernel_create()返回的socket。

    (2) skb:存放消息,它的data字段指向要发送的netlink消息结构,而 skb的控制块保存了消息的地址信息,宏NETLINK_CB(skb)就用于方便设置该控制块。

    (3) portid:pid端口。

    (4) nonblock:表示该函数是否为非阻塞,如果为1,该函数将在没有接收缓存可利用时立即返回;而如果为0,该函数在没有接收缓存可利用定时睡眠。


    多播发送接口:

    extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 portid,
                     __u32 group, gfp_t allocation);
    group:接收消息的多播组,该参数的每一个位代表一个多播组,因此如果发送给多个多播组;
    allocation:内存分配类型,一般地为GFP_ATOMIC或GFP_KERNEL,GFP_ATOMIC用于原子的上下文(即不可以睡眠),而GFP_KERNEL用于非原子上下文。


    释放socket


    extern void netlink_kernel_release(struct sock *sk);

    用户层操作

    nlmsghdr结构常见操作:

    NLMSG_SPACE(len): 将len加上nlmsghdr头长度,并按4字节对齐;

    NLMSG_DATA(nlh): 返回数据区首地址;

    创建socke


    int netlink_create_socket(void)
    {
            //create a socket
            return socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST);
    }

    bind

    int netlink_bind(int sock_fd)
    {
            struct sockaddr_nl addr;
     
            memset(&addr, 0, sizeof(struct sockaddr_nl));
            addr.nl_family = AF_NETLINK;
            addr.nl_pid = TEST_PID;
            addr.nl_groups = 0;
     
            return bind(sock_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_nl));
    }

    发送接收:
    使用sendmsg、recvmsg发送接收数据


    ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
    ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);


    使用sendto、recvfrom发送接收数据


    ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                          const struct sockaddr *dest_addr, socklen_t addrlen);
    ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                            struct sockaddr *src_addr, socklen_t *addrlen);


    例:
    说明:用户层pid设置为100,应用层发送一条信息到内核,内核回复同样的信息;

    内核层:


    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/stat.h>
    #include <linux/kdev_t.h>
    #include <linux/fs.h>
    #include <linux/device.h>
    #include <linux/cdev.h>
    #include <asm/uaccess.h>
     
    #include <net/netlink.h>
    #include <net/sock.h>
     
    #define NETLINK_TEST (25)
     
    static dev_t devId;
    static struct class *cls = NULL;
    struct sock *nl_sk = NULL;
     
    static void
    hello_cleanup(void)
    {
            netlink_kernel_release(nl_sk);
            device_destroy(cls, devId);
            class_destroy(cls);
            unregister_chrdev_region(devId, 1);
    }
     
    static void
    netlink_send(int pid, uint8_t *message, int len)
    {
            struct sk_buff *skb_1;
            struct nlmsghdr *nlh;
     
            if(!message || !nl_sk) {
                    return;
            }
     
            skb_1 = alloc_skb(NLMSG_SPACE(len), GFP_KERNEL);
            if( !skb_1 ) {
                    printk(KERN_ERR "alloc_skb error!\n");
            }
     
            nlh = nlmsg_put(skb_1, 0, 0, 0, len, 0);
            NETLINK_CB(skb_1).portid = 0;
            NETLINK_CB(skb_1).dst_group = 0;
            memcpy(NLMSG_DATA(nlh), message, len);
            netlink_unicast(nl_sk, skb_1, pid, MSG_DONTWAIT);
    }
     
    static void
    netlink_input(struct sk_buff *__skb)
    {
            struct sk_buff *skb;
            char str[100];
            struct nlmsghdr *nlh;
     
            if( !__skb ) {
                    return;
            }
     
            skb = skb_get(__skb);
            if( skb->len < NLMSG_SPACE(0)) {
                    return;
            }
     
            nlh = nlmsg_hdr(skb);
            memset(str, 0, sizeof(str));
            memcpy(str, NLMSG_DATA(nlh), sizeof(str));
            printk(KERN_INFO "receive message (pid:%d):%s\n", nlh->nlmsg_pid, str);
            printk(KERN_INFO "space:%d\n", NLMSG_SPACE(0));
            printk(KERN_INFO "size:%d\n", nlh->nlmsg_len);
            netlink_send(nlh->nlmsg_pid, NLMSG_DATA(nlh), nlh->nlmsg_len - NLMSG_SPACE(0));
     
            return;
    }
     
    static __init int netlink_init(void)
    {
            int result;
            struct netlink_kernel_cfg nkc;
     
            printk(KERN_WARNING "netlink init start!\n");
     
            //动态注册设备号
            if(( result = alloc_chrdev_region(&devId, 0, 1, "stone-alloc-dev") ) != 0) {
                    printk(KERN_WARNING "register dev id error:%d\n", result);
                    goto err;
            } else {
                    printk(KERN_WARNING "register dev id success!\n");
            }
            //动态创建设备节点
            cls = class_create(THIS_MODULE, "stone-class");
            if(IS_ERR(cls)) {
                    printk(KERN_WARNING "create class error!\n");
                    goto err;
            }
            if(device_create(cls, NULL, devId, "", "hello%d", 0) == NULL) {
                    printk(KERN_WARNING "create device error!\n");
                    goto err;
            }
     
            //初始化netlink
            nkc.groups = 0;
            nkc.flags = 0;
            nkc.input = netlink_input;
            nkc.cb_mutex = NULL;
            nkc.bind = NULL;
            nkc.unbind = NULL;
            nkc.compare = NULL;
            nl_sk = netlink_kernel_create(&init_net, NETLINK_TEST, &nkc);
            if( !nl_sk ) {
                    printk(KERN_ERR "[netlink] create netlink socket error!\n");
                    goto err;
            }
     
            printk(KERN_ALERT "netlink init success!\n");
            return 0;
    err:
            hello_cleanup();
            return -1;
    }
     
    static __exit void netlink_exit(void)
    {
            hello_cleanup();
            printk(KERN_WARNING "netlink exit!\n");
    }
     
    module_init(netlink_init);
    module_exit(netlink_exit);
     
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("Stone");

    应用层1:

    #include <sys/stat.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/socket.h>
    #include <string.h>
    #include <asm/types.h>
    #include <linux/netlink.h>
    #include <linux/socket.h>
    #include <errno.h>
     
    #define NETLINK_TEST    (25)
    #define MAX_PAYLOAD     (1024)
    #define TEST_PID        (100)
     
    int netlink_create_socket(void)
    {
            //create a socket
            return socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST);
    }
     
    int netlink_bind(int sock_fd)
    {
            struct sockaddr_nl addr;
     
            memset(&addr, 0, sizeof(struct sockaddr_nl));
            addr.nl_family = AF_NETLINK;
            addr.nl_pid = TEST_PID;
            addr.nl_groups = 0;
     
            return bind(sock_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_nl));
    }
     
    int
    netlink_send_message(int sock_fd, const unsigned char *message, int len,
                                            unsigned int pid, unsigned int group)
    {
            struct nlmsghdr *nlh = NULL;
            struct sockaddr_nl dest_addr;
            struct iovec iov;
            struct msghdr msg;
     
            if( !message ) {
                    return -1;
            }
     
            //create message
            nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(len));
            if( !nlh ) {
                    perror("malloc");
                    return -2;
            }
            nlh->nlmsg_len = NLMSG_SPACE(len);
            nlh->nlmsg_pid = TEST_PID;
            nlh->nlmsg_flags = 0;
            memcpy(NLMSG_DATA(nlh), message, len);
     
            iov.iov_base = (void *)nlh;
            iov.iov_len = nlh->nlmsg_len;
            memset(&dest_addr, 0, sizeof(struct sockaddr_nl));
            dest_addr.nl_family = AF_NETLINK;
            dest_addr.nl_pid = pid;
            dest_addr.nl_groups = group;
     
            memset(&msg, 0, sizeof(struct msghdr));
            msg.msg_name = (void *)&dest_addr;
            msg.msg_namelen = sizeof(struct sockaddr_nl);
            msg.msg_iov = &iov;
            msg.msg_iovlen = 1;
     
            //send message
            if( sendmsg(sock_fd, &msg, 0) < 0 )
            {
                    printf("send error!\n");
                    free(nlh);
                    return -3;
            }
     
            free(nlh);
            return 0;
    }
     
    int
    netlink_recv_message(int sock_fd, unsigned char *message, int *len)
    {
            struct nlmsghdr *nlh = NULL;
            struct sockaddr_nl source_addr;
            struct iovec iov;
            struct msghdr msg;
     
            if( !message || !len ) {
                    return -1;
            }
     
            //create message
            nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
            if( !nlh ) {
                    perror("malloc");
                    return -2;
            }
            iov.iov_base = (void *)nlh;
            iov.iov_len = NLMSG_SPACE(MAX_PAYLOAD);
            memset(&source_addr, 0, sizeof(struct sockaddr_nl));
            memset(&msg, 0, sizeof(struct msghdr));
            msg.msg_name = (void *)&source_addr;
            msg.msg_namelen = sizeof(struct sockaddr_nl);
            msg.msg_iov = &iov;
            msg.msg_iovlen = 1;
     
            if ( recvmsg(sock_fd, &msg, 0) < 0 ) {
                    printf("recvmsg error!\n");
                    return -3;
            }
            *len = nlh->nlmsg_len - NLMSG_SPACE(0);
            memcpy(message, (unsigned char *)NLMSG_DATA(nlh), *len);
     
            free(nlh);
            return 0;
    }
     
    int
    main(int argc, char **argv)
    {
            int sock_fd;
            char buf[MAX_PAYLOAD];
            int len;
     
            if( argc < 2) {
                    printf("enter message!\n");
                    exit(EXIT_FAILURE);
            }
     
            sock_fd = netlink_create_socket();
            if(sock_fd == -1) {
                    printf("socket error!\n");
                    return -1;
            }
     
            if( netlink_bind(sock_fd) < 0 ) {
                    perror("bind");
                    close(sock_fd);
                    exit(EXIT_FAILURE);
            }
     
            netlink_send_message(sock_fd, argv[1], strlen(argv[1]) + 1, 0, 0);
            if( netlink_recv_message(sock_fd, buf, &len) == 0 ) {
                    printf("recv:%s len:%d\n", buf, len);
            }
     
            close(sock_fd);
            return 0;
    }

    上面例子讲的是使用sendmsg、recvmsg。在应用层我们同样可以使用sendto、recvfrom发送接收数据,操作模式和UDP通信非常相似,区别是为了能成功接收数据,我们同样需要使用bind()绑定自身地址,但对于UDP这不是必须的;

    应用层2:


    #include <sys/stat.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/socket.h>
    #include <string.h>
    #include <asm/types.h>
    #include <linux/netlink.h>
    #include <linux/socket.h>
    #include <errno.h>
     
    #define NETLINK_TEST    (25)
    #define MAX_PAYLOAD     (1024)
    #define TEST_PID        (100)
     
    int netlink_create_socket(void)
    {
            //create a socket
            return socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST);
    }
     
    int netlink_bind(int sock_fd)
    {
            struct sockaddr_nl addr;
     
            memset(&addr, 0, sizeof(struct sockaddr_nl));
            addr.nl_family = AF_NETLINK;
            addr.nl_pid = TEST_PID;
            addr.nl_groups = 0;
     
            return bind(sock_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_nl));
    }
     
    int
    netlink_send_message(int sock_fd, const unsigned char *message, int len,
                                            unsigned int pid, unsigned int group)
    {
            struct nlmsghdr *nlh = NULL;
            struct sockaddr_nl dest_addr;
     
            if( !message ) {
                    return -1;
            }
     
            //create message
            nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(len));
            if( !nlh ) {
                    perror("malloc");
                    return -2;
            }
            nlh->nlmsg_len = NLMSG_SPACE(len);
            nlh->nlmsg_pid = TEST_PID;
            nlh->nlmsg_flags = 0;
            memcpy(NLMSG_DATA(nlh), message, len);
     
            memset(&dest_addr, 0, sizeof(struct sockaddr_nl));
            dest_addr.nl_family = AF_NETLINK;
            dest_addr.nl_pid = pid;
            dest_addr.nl_groups = group;
     
            //send message
            if( sendto(sock_fd, nlh, nlh->nlmsg_len, 0, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_nl)) != nlh->nlmsg_len ) {
                    printf("send error!\n");
                    free(nlh);
                    return -3;
            }
     
            free(nlh);
            return 0;
    }
     
    int
    netlink_recv_message(int sock_fd, unsigned char *message, int *len)
    {
            struct nlmsghdr *nlh = NULL;
            struct sockaddr_nl src_addr;
            socklen_t addrlen = sizeof(struct sockaddr_nl);
     
            if( !message || !len ) {
                    return -1;
            }
     
            //create message
            nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
            if( !nlh ) {
                    perror("malloc");
                    return -2;
            }
            memset(&src_addr, 0, sizeof(struct sockaddr_nl));
            if( recvfrom(sock_fd, nlh, NLMSG_SPACE(MAX_PAYLOAD), 0, (struct sockaddr *)&src_addr, (socklen_t *)&addrlen) < 0 ) {
                    printf("recvmsg error!\n");
                    return -3;
            }
            *len = nlh->nlmsg_len - NLMSG_SPACE(0);
            memcpy(message, (unsigned char *)NLMSG_DATA(nlh), *len);
     
            free(nlh);
            return 0;
    }
     
    int
    main(int argc, char **argv)
    {
            int sock_fd;
            char buf[MAX_PAYLOAD];
            int len;
     
            if( argc < 2) {
                    printf("enter message!\n");
                    exit(EXIT_FAILURE);
            }
     
            sock_fd = netlink_create_socket();
            if(sock_fd == -1) {
                    printf("socket error!\n");
                    return -1;
            }
     
            if( netlink_bind(sock_fd) < 0 ) {
                    perror("bind");
                    close(sock_fd);
                    exit(EXIT_FAILURE);
            }
     
            netlink_send_message(sock_fd, argv[1], strlen(argv[1]) + 1, 0, 0);
            if( netlink_recv_message(sock_fd, buf, &len) == 0 ) {
                    printf("recv:%s len:%d\n", buf, len);
            }
     
            close(sock_fd);
            return 0;
    }

    ————————————————
    版权声明:本文为CSDN博主「stone8761」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/stone8761/article/details/72780863

    展开全文
  • 内核与用户空间通信有很多种通信方式,netlink是其中种,其余的还有/proc、ioctl、sockopt、共享内存等等。netlink的特点异步全双工。 netlink使用32位端口寻址,称为pid(与进程号没有关系),其中...

    (本章基于:Linux-4.4.0-37)

    内核与用户空间通信有很多种通信方式,netlink是其中一种,其余的还有/proc、ioctl、sockopt、共享内存等等。netlink的特点是异步全双工。


    netlink使用32位端口寻址,称为pid(与进程号没有关系),其中内核的pid地址为0,。netlink主要特性如下:

    1 支持全双工、异步通信(当然同步也支持)

    2 用户空间可使用标准的BSD socket接口(但netlink并没有屏蔽掉协议包的构造与解析过程,推荐使用libnl等第三方库)

    3 在内核空间使用专用的内核API接口

    4 支持多播(因此支持“总线”式通信,可实现消息订阅)

    5 在内核端可用于进程上下文与中断上下文


    基本数据结构


    [cpp] view plain copy
    1. struct msghdr {  
    2.     void         *msg_name;       /* optional address */  
    3.     socklen_t     msg_namelen;    /* size of address */  
    4.     struct iovec *msg_iov;        /* scatter/gather array */  
    5.     size_t        msg_iovlen;     /* # elements in msg_iov */  
    6.     void         *msg_control;    /* ancillary data, see below */  
    7.     size_t        msg_controllen; /* ancillary data buffer len */  
    8.     int           msg_flags;      /* flags (unused) */  
    9. };  
    10.   
    11. struct sockaddr_nl  
    12. {  
    13.     sa_family_t nl_family; /*该字段总是为AF_NETLINK */  
    14.     unsigned short nl_pad; /* 目前未用到,填充为0*/  
    15.     __u32 nl_pid; /* process pid */  
    16.     __u32 nl_groups; /* multicast groups mask */  
    17. };  
    struct sockaddr_nl是netlink通信地址,和我们通常socket编程中的sockaddr_in作用一样。pid表示通信端口,groups表示组,注意这里为希望加入多播组号的掩码,也就是说最多只支持32个组。
    [cpp] view plain copy
    1. struct nlmsghdr  
    2. {  
    3.     __u32 nlmsg_len; /* Length of message including header */  
    4.     __u16 nlmsg_type; /* Message content */  
    5.     __u16 nlmsg_flags; /* Additional flags */  
    6.     __u32 nlmsg_seq; /* Sequence number */  
    7.     __u32 nlmsg_pid; /* Sending process PID */  
    8. };  
    Netlink报文的数据区由消息头和消息体构成,struct nlmsghdr即为消息头,消息体接在消息头后。


    内核层操作

    创建socket

    [cpp] view plain copy
    1. static inline struct sock *  
    2. netlink_kernel_create(struct net *net, int unit, struct netlink_kernel_cfg *cfg);  
    net:  一般直接填&init_net

    unit:协议类型,可自定义,如#define NETLINK_TEST 25

    cfg:配置结构,类型如下:

    [cpp] view plain copy
    1. /* optional Netlink kernel configuration parameters */  
    2. struct netlink_kernel_cfg {  
    3.     unsigned int    groups;  
    4.     unsigned int    flags;  
    5.     void        (*input)(struct sk_buff *skb);  
    6.     struct mutex    *cb_mutex;  
    7.     int     (*bind)(struct net *net, int group);  
    8.     void        (*unbind)(struct net *net, int group);  
    9.     bool        (*compare)(struct net *net, struct sock *sk);  
    10. };  

    groups:组编号;

    input:接收回调函数,接收一个sk_buff结构,数据包含一个nlmsghdr协议头;

    return:返回一个sock结构,返回NULL表示创建失败;


    单播发送接口:

    [cpp] view plain copy
    1. extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 portid, int nonblock);  

    (1) ssk:为函数 netlink_kernel_create()返回的socket。

    (2) skb:存放消息,它的data字段指向要发送的netlink消息结构,而 skb的控制块保存了消息的地址信息,宏NETLINK_CB(skb)就用于方便设置该控制块。

    (3) portid:pid端口。

    (4) nonblock:表示该函数是否为非阻塞,如果为1,该函数将在没有接收缓存可利用时立即返回;而如果为0,该函数在没有接收缓存可利用定时睡眠。


    多播发送接口:

    [cpp] view plain copy
    1. extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 portid,  
    2.                  __u32 group, gfp_t allocation);  
    group:接收消息的多播组,该参数的每一个位代表一个多播组,因此如果发送给多个多播组;
    allocation:内存分配类型,一般地为GFP_ATOMIC或GFP_KERNEL,GFP_ATOMIC用于原子的上下文(即不可以睡眠),而GFP_KERNEL用于非原子上下文。


    释放socket

    [cpp] view plain copy
    1. extern void netlink_kernel_release(struct sock *sk);  


    用户层操作

    nlmsghdr结构常见操作:

    NLMSG_SPACE(len): 将len加上nlmsghdr头长度,并按4字节对齐;

    NLMSG_DATA(nlh): 返回数据区首地址;


    创建socke

    [cpp] view plain copy
    1. int netlink_create_socket(void)  
    2. {  
    3.         //create a socket  
    4.         return socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST);  
    5. }  

    bind

    [cpp] view plain copy
    1. int netlink_bind(int sock_fd)  
    2. {  
    3.         struct sockaddr_nl addr;  
    4.   
    5.         memset(&addr, 0, sizeof(struct sockaddr_nl));  
    6.         addr.nl_family = AF_NETLINK;  
    7.         addr.nl_pid = TEST_PID;  
    8.         addr.nl_groups = 0;  
    9.   
    10.         return bind(sock_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_nl));  
    11. }  

    发送接收:

    使用sendmsg、recvmsg发送接收数据

    [cpp] view plain copy
    1. ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);  
    2. ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);  


    使用sendto、recvfrom发送接收数据

    [cpp] view plain copy
    1. ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,  
    2.                       const struct sockaddr *dest_addr, socklen_t addrlen);  
    3. ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,  
    4.                         struct sockaddr *src_addr, socklen_t *addrlen);  


    例:

    说明:用户层pid设置为100,应用层发送一条信息到内核,内核回复同样的信息;

    内核层:

    [cpp] view plain copy
    1. #include <linux/init.h>  
    2. #include <linux/module.h>  
    3. #include <linux/stat.h>  
    4. #include <linux/kdev_t.h>  
    5. #include <linux/fs.h>  
    6. #include <linux/device.h>  
    7. #include <linux/cdev.h>  
    8. #include <asm/uaccess.h>  
    9.   
    10. #include <net/netlink.h>  
    11. #include <net/sock.h>  
    12.   
    13. #define NETLINK_TEST (25)  
    14.   
    15. static dev_t devId;  
    16. static struct class *cls = NULL;  
    17. struct sock *nl_sk = NULL;  
    18.   
    19. static void  
    20. hello_cleanup(void)  
    21. {  
    22.         netlink_kernel_release(nl_sk);  
    23.         device_destroy(cls, devId);  
    24.         class_destroy(cls);  
    25.         unregister_chrdev_region(devId, 1);  
    26. }  
    27.   
    28. static void  
    29. netlink_send(int pid, uint8_t *message, int len)  
    30. {  
    31.         struct sk_buff *skb_1;  
    32.         struct nlmsghdr *nlh;  
    33.   
    34.         if(!message || !nl_sk) {  
    35.                 return;  
    36.         }  
    37.   
    38.         skb_1 = alloc_skb(NLMSG_SPACE(len), GFP_KERNEL);  
    39.         if( !skb_1 ) {  
    40.                 printk(KERN_ERR "alloc_skb error!\n");  
    41.         }  
    42.   
    43.         nlh = nlmsg_put(skb_1, 0, 0, 0, len, 0);  
    44.         NETLINK_CB(skb_1).portid = 0;  
    45.         NETLINK_CB(skb_1).dst_group = 0;  
    46.         memcpy(NLMSG_DATA(nlh), message, len);  
    47.         netlink_unicast(nl_sk, skb_1, pid, MSG_DONTWAIT);  
    48. }  
    49.   
    50. static void  
    51. netlink_input(struct sk_buff *__skb)  
    52. {  
    53.         struct sk_buff *skb;  
    54.         char str[100];  
    55.         struct nlmsghdr *nlh;  
    56.   
    57.         if( !__skb ) {  
    58.                 return;  
    59.         }  
    60.   
    61.         skb = skb_get(__skb);  
    62.         if( skb->len < NLMSG_SPACE(0)) {  
    63.                 return;  
    64.         }  
    65.   
    66.         nlh = nlmsg_hdr(skb);  
    67.         memset(str, 0, sizeof(str));  
    68.         memcpy(str, NLMSG_DATA(nlh), sizeof(str));  
    69.         printk(KERN_INFO "receive message (pid:%d):%s\n", nlh->nlmsg_pid, str);  
    70.         printk(KERN_INFO "space:%d\n", NLMSG_SPACE(0));  
    71.         printk(KERN_INFO "size:%d\n", nlh->nlmsg_len);  
    72.         netlink_send(nlh->nlmsg_pid, NLMSG_DATA(nlh), nlh->nlmsg_len - NLMSG_SPACE(0));  
    73.   
    74.         return;  
    75. }  
    76.   
    77. static __init int netlink_init(void)  
    78. {  
    79.         int result;  
    80.         struct netlink_kernel_cfg nkc;  
    81.   
    82.         printk(KERN_WARNING "netlink init start!\n");  
    83.   
    84.         //动态注册设备号  
    85.         if(( result = alloc_chrdev_region(&devId, 0, 1, "stone-alloc-dev") ) != 0) {  
    86.                 printk(KERN_WARNING "register dev id error:%d\n", result);  
    87.                 goto err;  
    88.         } else {  
    89.                 printk(KERN_WARNING "register dev id success!\n");  
    90.         }  
    91.         //动态创建设备节点  
    92.         cls = class_create(THIS_MODULE, "stone-class");  
    93.         if(IS_ERR(cls)) {  
    94.                 printk(KERN_WARNING "create class error!\n");  
    95.                 goto err;  
    96.         }  
    97.         if(device_create(cls, NULL, devId, """hello%d", 0) == NULL) {  
    98.                 printk(KERN_WARNING "create device error!\n");  
    99.                 goto err;  
    100.         }  
    101.   
    102.         //初始化netlink  
    103.         nkc.groups = 0;  
    104.         nkc.flags = 0;  
    105.         nkc.input = netlink_input;  
    106.         nkc.cb_mutex = NULL;  
    107.         nkc.bind = NULL;  
    108.         nkc.unbind = NULL;  
    109.         nkc.compare = NULL;  
    110.         nl_sk = netlink_kernel_create(&init_net, NETLINK_TEST, &nkc);  
    111.         if( !nl_sk ) {  
    112.                 printk(KERN_ERR "[netlink] create netlink socket error!\n");  
    113.                 goto err;  
    114.         }  
    115.   
    116.         printk(KERN_ALERT "netlink init success!\n");  
    117.         return 0;  
    118. err:  
    119.         hello_cleanup();  
    120.         return -1;  
    121. }  
    122.   
    123. static __exit void netlink_exit(void)  
    124. {  
    125.         hello_cleanup();  
    126.         printk(KERN_WARNING "netlink exit!\n");  
    127. }  
    128.   
    129. module_init(netlink_init);  
    130. module_exit(netlink_exit);  
    131.   
    132. MODULE_LICENSE("GPL");  
    133. MODULE_AUTHOR("Stone");  

    应用层1:

    [cpp] view plain copy
    1. #include <sys/stat.h>  
    2. #include <unistd.h>  
    3. #include <stdio.h>  
    4. #include <stdlib.h>  
    5. #include <sys/socket.h>  
    6. #include <string.h>  
    7. #include <asm/types.h>  
    8. #include <linux/netlink.h>  
    9. #include <linux/socket.h>  
    10. #include <errno.h>  
    11.   
    12. #define NETLINK_TEST    (25)  
    13. #define MAX_PAYLOAD     (1024)  
    14. #define TEST_PID        (100)  
    15.   
    16. int netlink_create_socket(void)  
    17. {  
    18.         //create a socket  
    19.         return socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST);  
    20. }  
    21.   
    22. int netlink_bind(int sock_fd)  
    23. {  
    24.         struct sockaddr_nl addr;  
    25.   
    26.         memset(&addr, 0, sizeof(struct sockaddr_nl));  
    27.         addr.nl_family = AF_NETLINK;  
    28.         addr.nl_pid = TEST_PID;  
    29.         addr.nl_groups = 0;  
    30.   
    31.         return bind(sock_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_nl));  
    32. }  
    33.   
    34. int  
    35. netlink_send_message(int sock_fd, const unsigned char *message, int len,  
    36.                                         unsigned int pid, unsigned int group)  
    37. {  
    38.         struct nlmsghdr *nlh = NULL;  
    39.         struct sockaddr_nl dest_addr;  
    40.         struct iovec iov;  
    41.         struct msghdr msg;  
    42.   
    43.         if( !message ) {  
    44.                 return -1;  
    45.         }  
    46.   
    47.         //create message  
    48.         nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(len));  
    49.         if( !nlh ) {  
    50.                 perror("malloc");  
    51.                 return -2;  
    52.         }  
    53.         nlh->nlmsg_len = NLMSG_SPACE(len);  
    54.         nlh->nlmsg_pid = TEST_PID;  
    55.         nlh->nlmsg_flags = 0;  
    56.         memcpy(NLMSG_DATA(nlh), message, len);  
    57.   
    58.         iov.iov_base = (void *)nlh;  
    59.         iov.iov_len = nlh->nlmsg_len;  
    60.         memset(&dest_addr, 0, sizeof(struct sockaddr_nl));  
    61.         dest_addr.nl_family = AF_NETLINK;  
    62.         dest_addr.nl_pid = pid;  
    63.         dest_addr.nl_groups = group;  
    64.   
    65.         memset(&msg, 0, sizeof(struct msghdr));  
    66.         msg.msg_name = (void *)&dest_addr;  
    67.         msg.msg_namelen = sizeof(struct sockaddr_nl);  
    68.         msg.msg_iov = &iov;  
    69.         msg.msg_iovlen = 1;  
    70.   
    71.         //send message  
    72.         if( sendmsg(sock_fd, &msg, 0) < 0 )  
    73.         {  
    74.                 printf("send error!\n");  
    75.                 free(nlh);  
    76.                 return -3;  
    77.         }  
    78.   
    79.         free(nlh);  
    80.         return 0;  
    81. }  
    82.   
    83. int  
    84. netlink_recv_message(int sock_fd, unsigned char *message, int *len)  
    85. {  
    86.         struct nlmsghdr *nlh = NULL;  
    87.         struct sockaddr_nl source_addr;  
    88.         struct iovec iov;  
    89.         struct msghdr msg;  
    90.   
    91.         if( !message || !len ) {  
    92.                 return -1;  
    93.         }  
    94.   
    95.         //create message  
    96.         nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));  
    97.         if( !nlh ) {  
    98.                 perror("malloc");  
    99.                 return -2;  
    100.         }  
    101.         iov.iov_base = (void *)nlh;  
    102.         iov.iov_len = NLMSG_SPACE(MAX_PAYLOAD);  
    103.         memset(&source_addr, 0, sizeof(struct sockaddr_nl));  
    104.         memset(&msg, 0, sizeof(struct msghdr));  
    105.         msg.msg_name = (void *)&source_addr;  
    106.         msg.msg_namelen = sizeof(struct sockaddr_nl);  
    107.         msg.msg_iov = &iov;  
    108.         msg.msg_iovlen = 1;  
    109.   
    110.         if ( recvmsg(sock_fd, &msg, 0) < 0 ) {  
    111.                 printf("recvmsg error!\n");  
    112.                 return -3;  
    113.         }  
    114.         *len = nlh->nlmsg_len - NLMSG_SPACE(0);  
    115.         memcpy(message, (unsigned char *)NLMSG_DATA(nlh), *len);  
    116.   
    117.         free(nlh);  
    118.         return 0;  
    119. }  
    120.   
    121. int  
    122. main(int argc, char **argv)  
    123. {  
    124.         int sock_fd;  
    125.         char buf[MAX_PAYLOAD];  
    126.         int len;  
    127.   
    128.         if( argc < 2) {  
    129.                 printf("enter message!\n");  
    130.                 exit(EXIT_FAILURE);  
    131.         }  
    132.   
    133.         sock_fd = netlink_create_socket();  
    134.         if(sock_fd == -1) {  
    135.                 printf("socket error!\n");  
    136.                 return -1;  
    137.         }  
    138.   
    139.         if( netlink_bind(sock_fd) < 0 ) {  
    140.                 perror("bind");  
    141.                 close(sock_fd);  
    142.                 exit(EXIT_FAILURE);  
    143.         }  
    144.   
    145.         netlink_send_message(sock_fd, argv[1], strlen(argv[1]) + 1, 0, 0);  
    146.         if( netlink_recv_message(sock_fd, buf, &len) == 0 ) {  
    147.                 printf("recv:%s len:%d\n", buf, len);  
    148.         }  
    149.   
    150.         close(sock_fd);  
    151.         return 0;  
    152. }  

    上面例子讲的是使用sendmsg、recvmsg。在应用层我们同样可以使用sendto、recvfrom发送接收数据,操作模式和UDP通信非常相似,区别是为了能成功接收数据,我们同样需要使用bind()绑定自身地址,但对于UDP这不是必须的;


    应用层2:

    [cpp] view plain copy
    1. #include <sys/stat.h>  
    2. #include <unistd.h>  
    3. #include <stdio.h>  
    4. #include <stdlib.h>  
    5. #include <sys/socket.h>  
    6. #include <string.h>  
    7. #include <asm/types.h>  
    8. #include <linux/netlink.h>  
    9. #include <linux/socket.h>  
    10. #include <errno.h>  
    11.   
    12. #define NETLINK_TEST    (25)  
    13. #define MAX_PAYLOAD     (1024)  
    14. #define TEST_PID        (100)  
    15.   
    16. int netlink_create_socket(void)  
    17. {  
    18.         //create a socket  
    19.         return socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST);  
    20. }  
    21.   
    22. int netlink_bind(int sock_fd)  
    23. {  
    24.         struct sockaddr_nl addr;  
    25.   
    26.         memset(&addr, 0, sizeof(struct sockaddr_nl));  
    27.         addr.nl_family = AF_NETLINK;  
    28.         addr.nl_pid = TEST_PID;  
    29.         addr.nl_groups = 0;  
    30.   
    31.         return bind(sock_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_nl));  
    32. }  
    33.   
    34. int  
    35. netlink_send_message(int sock_fd, const unsigned char *message, int len,  
    36.                                         unsigned int pid, unsigned int group)  
    37. {  
    38.         struct nlmsghdr *nlh = NULL;  
    39.         struct sockaddr_nl dest_addr;  
    40.   
    41.         if( !message ) {  
    42.                 return -1;  
    43.         }  
    44.   
    45.         //create message  
    46.         nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(len));  
    47.         if( !nlh ) {  
    48.                 perror("malloc");  
    49.                 return -2;  
    50.         }  
    51.         nlh->nlmsg_len = NLMSG_SPACE(len);  
    52.         nlh->nlmsg_pid = TEST_PID;  
    53.         nlh->nlmsg_flags = 0;  
    54.         memcpy(NLMSG_DATA(nlh), message, len);  
    55.   
    56.         memset(&dest_addr, 0, sizeof(struct sockaddr_nl));  
    57.         dest_addr.nl_family = AF_NETLINK;  
    58.         dest_addr.nl_pid = pid;  
    59.         dest_addr.nl_groups = group;  
    60.   
    61.         //send message  
    62.         if( sendto(sock_fd, nlh, nlh->nlmsg_len, 0, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_nl)) != nlh->nlmsg_len ) {  
    63.                 printf("send error!\n");  
    64.                 free(nlh);  
    65.                 return -3;  
    66.         }  
    67.   
    68.         free(nlh);  
    69.         return 0;  
    70. }  
    71.   
    72. int  
    73. netlink_recv_message(int sock_fd, unsigned char *message, int *len)  
    74. {  
    75.         struct nlmsghdr *nlh = NULL;  
    76.         struct sockaddr_nl src_addr;  
    77.         socklen_t addrlen = sizeof(struct sockaddr_nl);  
    78.   
    79.         if( !message || !len ) {  
    80.                 return -1;  
    81.         }  
    82.   
    83.         //create message  
    84.         nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));  
    85.         if( !nlh ) {  
    86.                 perror("malloc");  
    87.                 return -2;  
    88.         }  
    89.         memset(&src_addr, 0, sizeof(struct sockaddr_nl));  
    90.         if( recvfrom(sock_fd, nlh, NLMSG_SPACE(MAX_PAYLOAD), 0, (struct sockaddr *)&src_addr, (socklen_t *)&addrlen) < 0 ) {  
    91.                 printf("recvmsg error!\n");  
    92.                 return -3;  
    93.         }  
    94.         *len = nlh->nlmsg_len - NLMSG_SPACE(0);  
    95.         memcpy(message, (unsigned char *)NLMSG_DATA(nlh), *len);  
    96.   
    97.         free(nlh);  
    98.         return 0;  
    99. }  
    100.   
    101. int  
    102. main(int argc, char **argv)  
    103. {  
    104.         int sock_fd;  
    105.         char buf[MAX_PAYLOAD];  
    106.         int len;  
    107.   
    108.         if( argc < 2) {  
    109.                 printf("enter message!\n");  
    110.                 exit(EXIT_FAILURE);  
    111.         }  
    112.   
    113.         sock_fd = netlink_create_socket();  
    114.         if(sock_fd == -1) {  
    115.                 printf("socket error!\n");  
    116.                 return -1;  
    117.         }  
    118.   
    119.         if( netlink_bind(sock_fd) < 0 ) {  
    120.                 perror("bind");  
    121.                 close(sock_fd);  
    122.                 exit(EXIT_FAILURE);  
    123.         }  
    124.   
    125.         netlink_send_message(sock_fd, argv[1], strlen(argv[1]) + 1, 0, 0);  
    126.         if( netlink_recv_message(sock_fd, buf, &len) == 0 ) {  
    127.                 printf("recv:%s len:%d\n", buf, len);  
    128.         }  
    129.   
    130.         close(sock_fd);  
    131.         return 0;  
    132. }  

    展开全文
  • 串行通信作为计算机通信方式之一,主要起到主机与外设以及主机之间的数据传输作用,串行通信具有传输线少、成本低的特点,主要适用于近距离的人-机交换、实时监控等系统通信工作当中,借助于现有的电话网也能实现远...
  • 在理解了四种通信模型工作特点和区别后,对于我们后文介绍搭建在其上各种通信框架,集成思想都是有益。 目前常用IO通信模型包括四种(这里说都是网络IO):阻塞式同步IO、非阻塞式同步IO、多路复用IO、...
  • kafka学习路(

    2021-01-21 23:20:14
    我喜欢带着问题去学习,所以以Q&...异步通信 Q&A eq.1 问:kafka是如何快速查找数据? 答:两个重要概念:kafka数据存储结构以及偏移量。 1. kafka数据落盘形式是每个partition为.
  • 消息队列是种应用间的通信方式,消息发送后可以立即返回,由消息系统来确保消息可靠传递。消息队列是异步协作机制。应用场景:订单系统,用户点击按钮后,扣减库存,生成响应数据,发送红包,发送短息通知。...
  • FPGAUART串口实验

    2021-01-06 21:16:23
    UART:是种采用异步串行通信方式的通用异步收发传输器,它在发送数据时将并行数据转换成串行数据来传输,在接收数据时将接收到的串行数据转换成并行数据。 UART在发送或接收过程中的帧数据由4部分组成, 起始...
  • 让Fractal以优雅和简洁的方式来构建您想法。 TLDR 我们使用更好工具,我们快速前进,我们热爱创新...哦,Fractal是分形,这意味着您可以轻松地将任何Fractal应用程序嵌入另个应用程序中。 产品特点 可扩展...
  • 电子邮箱是外贸人常用的订单处理及拓客的方式工具,由于其异步通信的特点,还有国际往来的及时性,成为了很多外贸人极为重视的拓客方式工具。 外贸行业用邮箱,同行会多涉及客户拓展、订单处理两个部分,由于频繁的...
  • 1.1.5 单片机的特点及应用 1.2 单片机应用系统概述 1.2.1 单片机应用系统的种类 1.2.2 单片机控制系统的组成 1.2.3 单片机应用系统的开发过程 1.3 单片机开发板B简介 1.3.1 单片机开发板B的功能 1.3.2 单片机开发板B...
  • 1.1.5 单片机的特点及应用 1.2 单片机应用系统概述 1.2.1 单片机应用系统的种类 1.2.2 单片机控制系统的组成 1.2.3 单片机应用系统的开发过程 1.3 单片机开发板B简介 1.3.1 单片机开发板B的功能 1.3.2 单片机开发板B...
  • 文章目录数据通信异步通信传送方式终端概述控制台伪终端终端体系终端体系---串口数据流串口驱动描述串口驱动注册UART端口描述操作串口添加端口串口驱动程序设计 在介绍终端控制体系之前,要先普及 一下数据通信...
  • Hadoopkafka总结

    2021-03-14 08:21:55
    消息队列具有特点:解耦,冗余,扩展性,缓冲,异步通信等。 kafka里面一些专有名称:生产者,消费者,topic,partition,broker(个Kafka服务器就是个broker) 、kafka概述: 1、消息队列: 1)、原理...
  • 总结了微服务应该具备的特点: - 小, 且专注于做⼀件事情 - 独立的进程 - 松耦合、独立部署 - 轻量级的通信机制 - 有边界: 服务间边界清晰、灵活选择语言和技术(这个是有争议的) - 松...
  • 所有操作都要完成或出错才会返回,不过偶执着被大家称为阻塞,实在是郁闷~~(场下一片嘘声),其实这样也是有好处,比如逻辑清晰,编程比较容易。 在服务器端,我会做个socket交给acceptor对象,让它一直等...
  • boost::asio编程-同步TCP

    千次阅读 2014-12-17 10:47:56
    boost.asio库是个跨平台网络及底层IOC++编程库,它使用现代C++手法实现了统一的异步调用模型。 boost.asio库支持TCP、UDP、ICMP通信协议。 下面介绍同步TCP模式: 大家好!我是同步方式! 我...
  • 消息队列是应用系统之间通信的方法,本质是队列,具有先进先出(FIFO)的特点,队列的元素是消息,所以叫消息队列,是种中间件。 应用场景 场景说明:用户注册后,需要发送邮件和短信,然后返回客户端完成验证,...
  • 消息队列是用于任务与任务,中断与任务之间通信的数据结构,具有不定长,异步的特点。消息队列支持先进先出方式,先进入消息队列的消息先传给任务,同时也支持后进先出方式,即往队首发送消息。 个消息队列 = 控制...
  • Java技术回顾JMS:JMS概念和模型

    千次阅读 2008-01-13 18:23:00
    、JMS相关概念1、企业消息系统:也称消息中间件(MOM,Message-Oriented Middleware),它允许应用程序之间通过消息的方式进行通信,它具有两个显著的特点:应用程序之间通过虚拟的通道Destination来交换消息,发送...
  • 如发现有差错,数据链路层就丢弃这个出了差错帧,然后采取下面两种方法之一:或者不作任何其他处理;或者由数据链路层通知对方重传这一帧,直到正确无误地收到此帧为止。” 可见,如果选择前一种方法,即不作...
  • C++封装Linux消息队列

    千次阅读 2015-09-03 21:41:36
    消息队列是Linux进程间通信方式之一,在面向对象编程中,需要对其封装。 一、消息队列的特点 1、异步通信,消息队列会保存进程发送的消息,其他进程不一定要及时取走消息。 2、可以发送不同类型的消息,消息的...
  • boost.asio库是个跨平台网络及底层IOC++编程库,它使用现代C++手法实现了统一的异步调用模型。 boost.asio库支持TCP、UDP、ICMP通信协议。 下面介绍同步TCP模式: 大家好!我是同步方式! 我主要特点...
  • 抽象包括两个方面,一是过程抽象,二是数据抽象。 2.继承:  继承是一种联结类层次模型,并且允许和鼓励类重用,它提供了一种明确表述共性方法。对象一个新类可以从现有类中派生,这个过程称为类继承...

空空如也

空空如也

1 2 3 4 5
收藏数 81
精华内容 32
关键字:

异步通信方式的特点之一是