无论传感器的协议是什么,只要下位机可以转换为以太网数据包,我们的Data Driver驱动层都可以接收到数据并且处理。现在我们需要实现像Posix API那样的接口函数,用来写服务器接收和处理数据。这里内容比较多,分两天实现。

Unix UDP

先来看一下正常的Linux网络编程的UDP Server和相关的Posix API

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>

#define UDP_RECV_BUF_SIZE    1024

int main(int argc, char* argv[]) {

    int fd = socket(AF_INET, SOCK_DGRAM, 0);

    if (fd < 0) {

        printf("Create socket failed\n");
    }

    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(struct sockaddr_in));
    servaddr.sin_port = htons(9999);
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = inet_addr("192.168.207.133");

    bind(fd, (struct sockaddr*)&servaddr, sizeof(struct sockaddr));

    char buf[UDP_RECV_BUF_SIZE] = {0};
    struct sockaddr_in cltaddr;
    socklen_t len = sizeof(cltaddr);

    while (1) {

        if (recvfrom(fd, buf, UDP_RECV_BUF_SIZE, 0, (struct sockaddr*)&cltaddr, &len) < 0) {

            continue;
        }
        else {

            printf("recv from %s:%d %s\n", inet_ntoa(cltaddr.sin_addr), ntohs(cltaddr.sin_port), buf);
            sendto(fd, buf, strlen(buf), 0, (struct sockaddr*)&cltaddr, len);

            memset(buf, 0, UDP_RECV_BUF_SIZE);
        }
    }
    close(fd);
    return 0;
}

https://imagehyj.oss-cn-hangzhou.aliyuncs.com/blog/20240726002958.png

相关API

  • int socket(int domain, int type, int protocol);

  • domain:指定协议族,常用的有AF_INET(IPv4)、AF_INET6(IPv6)等。

  • type:指定套接字类型,常用的有SOCK_STREAM(TCP流式套接字)、SOCK_DGRAM(UDP数据报套接字)等。\

  • protocol:指定具体的协议,一般可以设置为0,在特定的domain和type下会自动选择合适的协议。

https://imagehyj.oss-cn-hangzhou.aliyuncs.com/blog/20240726004153.png

  • int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

  • sockfd:需要绑定的套接字描述符。

  • addr:要绑定的地址信息,类型为struct sockaddr结构体指针。通常使用struct sockaddr_in来表示IPv4地址,或者使用struct sockaddr_in6来表示IPv6地址。

  • addrlen:指定传入的地址结构体的长度。

https://imagehyj.oss-cn-hangzhou.aliyuncs.com/blog/20240726004422.png

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

  • sockfd:已绑定的套接字描述符。

  • buf:接收数据的缓冲区指针。

  • len:缓冲区的大小。

  • flags:附加选项,通常为0。

  • src_addr:发送方地址信息结构体指针,如果不需要获取发送方地址可以传入NULL。

  • addrlen:发送方地址信息结构体长度指针,如果不需要获取发送方地址可以传入NULL。

https://imagehyj.oss-cn-hangzhou.aliyuncs.com/blog/20240726004522.png

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

  • sockfd:已绑定的套接字描述符。

  • buf:要发送的数据缓冲区指针。

  • len:要发送的数据长度。

  • flags:附加选项,通常为0。

  • dest_addr:目标地址信息结构体指针,包含了目标IP地址和端口号等信息。

  • addrlen:目标地址信息结构体长度。

https://imagehyj.oss-cn-hangzhou.aliyuncs.com/blog/20240726004556.png

项目地址

项目地址