UNP——socket套接字分析以及IPC_UDS

2023-12-04 19:10
文章标签 分析 ipc socket uds 接字 unp

本文主要是介绍UNP——socket套接字分析以及IPC_UDS,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. socket流程

发送方:

  1. int socket(int domain, int type, int protocol);
  2. ssize_t sendto(int socket, const void *buffer, size_t length, int flags, const struct sockaddr *dest_addr, socklen_t dest_len);
  3. close

接收方:

  1. int socket(int domain, int type, int protocol);
  2. int bind(int socket, const struct sockaddr *address, socklen_t address_len);
  3. ssize_t recvfrom(int socket, void *restrict buffer, size_t length, int flags, struct sockaddr *restrict address, socklen_t *restrict address_len);
  4. close

注意,服务器需要绑定port,而一般客户端不需要,因为服务端的port一般是固定且众所周知的,而客户端是内核随机指定,不需要bind。rpc服务器除外。

2 注意点及相关函数分析

2.1 sockaddr与sockaddr_in

bind,sendto,recvfrom等函数都用到了sockaddr类型参数,sockaddr_in通过man 7 ip查看

struct sockaddr {unsigned short sa_family; /* address family, AF_xxx */char sa_data[14]; /* 14 bytes of protocol address */};

sa_data[14]包含套接字中的目标地址和端口信息,而sockaddr_in中,则将port,addr分隔开
一般先把sockaddr_in变量赋值后,强制类型转换后传入用sockaddr做参数的函数

struct sockaddr_in {sa_family_t    sin_family; /* address family: AF_INET */in_port_t      sin_port;   /* port in network byte order */struct in_addr sin_addr;   /* internet address */};/* Internet address. */struct in_addr {uint32_t       s_addr;     /* address in network byte order */};

2.2 htons htonl ntohs ntohl

htons为 host to net short 主机字节顺序转换为网络字节顺序,且参数为uint16_t
ntohl为 net to host long相反,参数为uint32_t

网络字节序 Network Order

TCP/IP各层协议将字节序定义为Big-Endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序。

主机序 Host Orader

它遵循Little-Endian规则。所以当两台主机之间要通过TCP/IP协议进行通信的时候就需要调用相应的函数进行主机序(Little-Endian)和网络序(Big-Endian)的转换。

这里要区分几个概念,大小端,最有效位优先MSBF,最有效位MSB,LSB等

  1. 大端:
    在这里插入图片描述
  2. 小端
    在这里插入图片描述
  3. MSB,LSB
    最高有效位和最低有效位,最右的0A为MSB,0D为LSB
  4. MSBF 等同于大端, MSB在内存的最前,即MSB在低地址,为大端

2.3 inet_pton,inet_ntop

上述两个函数将IP地址在“点分十进制”和“二进制整数”之间转换
inet_ntop将点分ip转换成二进制整数,供sockaddr_in中sin_addr使用

const char * inet_ntop(int af, const void * restrict src, char * restrict dst,socklen_t size);

inet_pton则相反,将sockaddr_in中的sin_addr转换成点分ip地址,如"172.16.9.6"

int inet_pton(int af, const char * restrict src, void * restrict dst);

注意,不能使用atoi或者itoa,这两个函数是转换convert ASCII string to integer或者反向,而"172.16.9.6"非一般字符串,为点分的字符串

int atoi(const char *str);

2.4 setsockopt

	   #include <sys/types.h>          /* See NOTES */#include <sys/socket.h>int getsockopt(int sockfd, int level, int optname,void *optval, socklen_t *optlen);int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);

setsockopt设置socket options,通过man 7 socket、IP、UDP、TCP等查看其属性,如果设置broadcast,则man 7 socket,其有SO_BROADCAST等属性,设置其flag,注意有些属性的,如man 7 ip,IP_ADD_MEMBERSHIP加入组播组,其参数为结构体,如下,所以要设置optlen

 struct ip_mreqn {struct in_addr imr_multiaddr; /* IP multicast groupaddress */struct in_addr imr_address;   /* IP address of localinterface */int            imr_ifindex;   /* interface index */};
2.4.1 设置组播

需要注意点:
A 发送组播到sendto 235.2.3.5(1990)
B 接受recvfrom ,本地port 也必须是1990才能收到
相关函数可以通过man 7 ip查看
发送方:
1. 设置组播组接口属性,setsockopt(sd,IPPROTO_IP,IP_MULTICAST_IF,&mreq,sizeof(mreq))
如果不调用该函数表示使用默认接口,如果调用,可以使用 addr.imr_ifindex = if_nametoindex(“eth0”) 设置接口为eth0,且可以设置ip地址等。
在这里插入图片描述
接收方:
1. 加入组播组,setsockopt(sd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq)
在这里插入图片描述
需要注意的点在于如下结构体,Linux系统多播发送和接收,这是别人文章引用

/* Internet address.  */
typedef uint32_t in_addr_t;
struct in_addr
{in_addr_t s_addr;
};// ip_mreq是一个旧的数据结构,但目前仍然可用
struct ip_mreq
{/* IP multicast address of group.  */struct in_addr imr_multiaddr;// 设置加入多播组的的网卡ip, 注意这里并不表示socket同该网卡绑定// 该socket仍然能够接收到不是该网卡的数据包,该设置仅仅表示该ip// 对应的网卡能够接收对应多播组的数据包struct in_addr imr_interface;
};// ip_mreqn是从Linux 2.2之后可用的新的数据结构,相比ip_mreq,其多了一个imr_ifindexy
struct ip_mreqn {struct in_addr imr_multiaddr;// 设置加入多播组的的网卡ip, 注意这里并不表示socket同该网卡绑定// 该socket仍然能够接收到不是该网卡的数据包,该设置仅仅表示该ip// 对应的网卡能够接收对应多播组的数据包struct in_addr imr_address;   // 设置加入多播组的网卡的index,该设置项优先级高于上边的网卡ipint            imr_ifindex; 
};

别人文章描述,懒得码字了
TCP中bind()的意思是将该socket绑定到某个IP:PORT上,组播的意思是socket只接收该组播组的数据包。如果这里绑定的是INADDR_ANY, 这个socket就讲接收到能听到的所有组播组IP相同端口的数据包, 即组播IP不同,端口相同时,组播串线的情况。
如果这里绑定的是某个具体组播组的IP, 这里内核向socket发送数据的时候就会过滤掉不是该组播组的数据。

IP_ADD_MEMBERSHIP意思是加入组播组。 根据IGMP协议,主机将会向组播管理端发送一个报文,报告本机要加入某个交换机,交换机就会向相应的端口转发这个组播组的数据包。 group.imr_multiaddr.s_addr为组播组IP。
group.imr_interface.s_addr一般写要加入组播组主机的接口/网卡的 IP, 以确定收取哪一个子网的组播信息,会通过该接口接收组播包。如果设为INADDR_ANY(0.0.0.0),则使用默认的IPV4组播接口

之前项目中使用dlt-receive时,由于没设置组播imr_interface的ip,即没有选择网络接口号,从默认的ipv4组播接口收不到数据

    case DLT_CLIENT_MODE_UDP_MULTICAST:if ((client->sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0){dlt_vlog(LOG_ERR,"%s: ERROR: socket error: %s\n",__func__,strerror(errno));return DLT_RETURN_ERROR;}/* allow multiple sockets to use the same PORT number */if (setsockopt(client->sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0){dlt_vlog(LOG_ERR,"%s: ERROR: Reusing address failed: %s\n",__func__,strerror(errno));return DLT_RETURN_ERROR;}memset(&client->receiver.addr, 0, sizeof(client->receiver.addr));client->receiver.addr.sin_family = AF_INET;client->receiver.addr.sin_addr.s_addr = htonl(INADDR_ANY);client->receiver.addr.sin_port = htons(client->port);/* bind to receive address */if (bind(client->sock, (struct sockaddr*) &client->receiver.addr, sizeof(client->receiver.addr)) < 0){dlt_vlog(LOG_ERR,"%s: ERROR: bind failed: %s\n",__func__,strerror(errno));return DLT_RETURN_ERROR;}mreq.imr_interface.s_addr = htonl(INADDR_ANY);if (client->hostip){mreq.imr_interface.s_addr = inet_addr(client->hostip);}if (client->servIP == NULL){dlt_vlog(LOG_ERR,"%s: ERROR: server address not set\n",__func__);return DLT_RETURN_ERROR;}char delimiter[] = ",";char* servIP = strtok(client->servIP, delimiter);while(servIP != NULL) {mreq.imr_multiaddr.s_addr = inet_addr(servIP);if (mreq.imr_multiaddr.s_addr == (in_addr_t)-1){dlt_vlog(LOG_ERR,"%s: ERROR: server address not not valid %s\n",__func__,servIP);return DLT_RETURN_ERROR;}if (setsockopt(client->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0){dlt_vlog(LOG_ERR,"%s: ERROR: setsockopt add membership failed: %s\n",__func__,strerror(errno));return DLT_RETURN_ERROR;}servIP = strtok(NULL, delimiter);}receiver_type = DLT_RECEIVE_UDP_SOCKET;break;
2.4.2 设置广播

发送方和接收方均需要设置SO_BROADCAST,通过man 7 socket查看
在这里插入图片描述

2.5 可变长数组

下面例子中使用了可变长数组,发送和接收并不知道传输数据的长度

typedef struct msg_st
{uint32_t math;uint32_t chinese;uint8_t name[];  //可变长度数组
}test_st

此时,sizeof(test_st)为8,name[]数组并不占据空间大小,只有当malloc时,才确定

ize = sizeof(struct msg_st)+strlen(argv[2]);sndr_l = (struct msg_st*)malloc(size);

此时,分配了strlen(argv[2])的长度给name[]

代码分析

sndercopy.c


#include "protocopy.h"
#include <sys/types.h> 
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <string.h>
#include <net/if.h>
#define IPSTRSIZE 40int main(int argc, char* argv[]){int sd, size;struct sockaddr_in laddr,raddr;struct msg_st* sndr_l; //这里要使用msg_st*,因为使用了可变数组,数组长度未知,需要使用malloc动态申请内存socklen_t raddrlen;int flag = 1;if(argc < 3){fprintf(stderr,"Usage....\n");exit(1);}if(strlen(argv[2])>NAMEMAX){fprintf(stderr,"NAMEMAX error....\n");exit(1);}size = sizeof(struct msg_st)+strlen(argv[2]);sndr_l = (struct msg_st*)malloc(size); //动态申请内存长度为sizeof(msg_st)加上可变数组大小strcpy(sndr_l->name,argv[2]); //不能写sndr_l.name = "Alan",得用strcpysndr_l->math = htonl(rand()%100);sndr_l->chinese = htonl(rand()%100);raddr.sin_family = AF_INET;raddr.sin_port = htons(atoi(RCVPORT));inet_pton(AF_INET,argv[1],&raddr.sin_addr);sd = socket(AF_INET,SOCK_DGRAM,0);//创建广播//int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);if(setsockopt(sd,SOL_SOCKET,SO_BROADCAST,&flag,sizeof(flag))<0)//注意SO_BROADCAST对应的是flag,不同的opt可能有不同的参数类型,可能是结构体{perror("setsockopt_SO_BROADCAST");exit(1);}//创建组播组 IP_MULTICAST_IFstruct ip_mreqn mreq;inet_pton(AF_INET,MULTIGROUP,&mreq.imr_multiaddr); //多播ipinet_pton(AF_INET,"0.0.0.0",&mreq.imr_address); //本机ipmreq.imr_ifindex = if_nametoindex("eno1");//通过ip ad sh查看网络索引号,或者通过函数if_nametoindex将名字转换成索引号/*   struct ip_mreqn {struct in_addr imr_multiaddr; /* IP multicast groupaddress *//*              struct in_addr imr_address;   /* IP address of localinterface *//*              int            imr_ifindex;   /* interface index *///         };if(setsockopt(sd,IPPROTO_IP,IP_MULTICAST_IF,&mreq,sizeof(mreq))<0){perror("setsockopt_IP_MULTICAST_IF");exit(1);}//man 7 udp IP_ADD_MEMBERSHIP加入多播组等,man 7 socket Socket options--setsockopt或者getsockopt--SO_BROADCAST,//socket level  set to SOL_SOCKET for all sockets.if(sendto(sd,sndr_l,size,0,(void*)&raddr,sizeof(raddr))<0) //send是用在流式传输SOCK_STREAM{perror("sendto");exit(1);}fputs("ok",stderr);close(sd);free(sndr_l);exit(0);
}

recvercopy.c


#include "protocopy.h"
#include <sys/types.h> 
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <net/if.h>
#define IPSTRSIZE 40
int main(){int sd,size;int flag = 1;socklen_t raddr_len;char raddr_addr[IPSTRSIZE];struct sockaddr_in laddr, raddr;    //man 7 ipstruct msg_st* recvbuffer;size = sizeof(struct msg_st) + NAMEMAX;recvbuffer =(struct msg_st*) malloc(size);laddr.sin_family = AF_INET;laddr.sin_port = htons(atoi(RCVPORT)); //htons home to Network short ,atoi RCVPORTinet_pton(AF_INET,"0.0.0.0",&laddr.sin_addr);  // 把ip地址从char* 转换成 二进制数,sin_addr类型为in_addr为uint32_tsd = socket(AF_INET,SOCK_DGRAM,0);if(setsockopt(sd,SOL_SOCKET,SO_BROADCAST,&flag,sizeof(flag))<0){perror("setsockopt");exit(1);}struct ip_mreqn mreq;inet_pton(AF_INET,MULTIGROUP,&mreq.imr_multiaddr);inet_pton(AF_INET,"0.0.0.0",&mreq.imr_address);mreq.imr_ifindex = if_nametoindex("eno1");if(setsockopt(sd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq))<0){perror("setsockopt_IP_ADD_MEMBERSHIP");exit(1);}raddr_len = sizeof(raddr); //初始化给个大小if(sd < 0){perror("sd error");exit(1);}
//       int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);/*struct sockaddr_in {                                                man 7 ipsa_family_t    sin_family; /* address family: AF_IN
ET *//*           in_port_t      sin_port;   /* port in network byte 
order *//*          struct in_addr sin_addr;   /* internet address *///       };/* Internet address. *///   struct in_addr {//      uint32_t       s_addr;     /* address in network byte order *///  };if(bind(sd,(void*)&laddr,sizeof(laddr))<0){perror("bind()");exit(1);}while(1){recvfrom(sd ,recvbuffer,size,0,(void*)&raddr,&raddr_len);inet_ntop(AF_INET,&raddr.sin_addr,raddr_addr,IPSTRSIZE);fprintf(stderr,"-----Message From %s: %d----\n",raddr_addr,ntohs(raddr.sin_port));fprintf(stderr,"NAME = %s\n",recvbuffer->name);fprintf(stderr,"MATH = %d\n",ntohl(recvbuffer->math)); //多字节,跨网络要用ntohl,htonl等fprintf(stderr,"MATH = %d\n",ntohl(recvbuffer->chinese));}close(sd);free(recvbuffer);exit(0);
}

protocopy.h

#ifndef PROTOCOPY_H__
#define PROTOCOPY_H__#define MULTIGROUP "235.2.3.5"
#define RCVPORT "1990"
#define NAMEMAX (512-8-8)
typedef unsigned int   uint32_t;
typedef unsigned  char   uint8_t;
struct msg_st
{uint32_t math;uint32_t chinese;uint8_t name[];  //可变长度数组
}__attribute__((packed));  //位对齐#endif
ThinkStation-P310:~/Videos/lxz$ ./snderbroadcast 255.255.255.255 helloworld222222
ThinkStation-P310:~/Videos/lxz$ $ ./snderbroadcast 235.2.3.5 helloworld2222223333333
ThinkStation-P310:~/Videos/lxz$ $ ./snderbroadcast 127.0.0.1 helloworld22222233333334444444
-----Message From 10.64.4.49: 40728----
NAME = helloworld222222
MATH = 83
MATH = 86
-----Message From 127.0.0.1: 52268----
NAME = helloworld2222223333333
MATH = 83
MATH = 86
-----Message From 127.0.0.1: 46572----
NAME = helloworld22222233333334444444
MATH = 83
MATH = 86
^C

3. UDS进程间通信

下列代码源自https://blog.csdn.net/qq_22863733/article/details/80629920
注意,UDS与socket网络通信的区别在于

  1. UDS里,bind使用的struct sockaddr类型为struct sockaddr_un(AF_UNIX),而一般socket用的是sockaddr_in(AF_INET)
  2. bind的时候,创建S_IFSOCK的文件。该文件仅用于向客户端进程告知套接字名字,该文件不能打开,也不能由应用程序用于通信,当关闭套接字时,并不自动删除该文件,所以我们必须确保在应用程序终止前,对该文件执行解除链接操作(unlink(path)),或删除该文件。
  3. 发送数据时,指定接收方绑定的路径名,操作系统根据该路径名可以直接找到对应的接收方,并将原始数据直接拷贝到接收方的内核缓冲区中,并上报给接收方进程进行处理。同样的接收方可以从收到的数据包中获取到发送方的路径名,并通过此路径名向其发送数据。

在这里插入图片描述

 struct sockaddr_in {sa_family_t    sin_family; /* address family: AF_INET */in_port_t      sin_port;   /* port in network byte order */struct in_addr sin_addr;   /* internet address */};/* Internet address. */struct in_addr {uint32_t       s_addr;     /* address in network byte order */};
struct sockaddr_un {
sa_family_t     sun_family;     /* AF_UNIX */
char    sun_path[UNIX_PATH_MAX];        /* 路径名 */
};
 struct sockaddr_un sun;sun.sun_family = AF_LOCAL;    //1strcpy(sun.sun_path, filepath); //2bind(sockfd, (struct sockaddr*)&sun, sizeof(sun));

3.1 代码实例

server


#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{int server_sockfd, client_sockfd;int server_len, client_len;struct sockaddr_un server_address;struct sockaddr_un client_address;int i,byte,ch_send;char recv_buf[128];char send_buf[128] = "ACK";unlink("server_socket");	//解除原有server_socket对象链接server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);//创建socket,指定通信协议为AF_UNIX,数据方式SOCK_STREAM//配置server_addressserver_address.sun_family = AF_UNIX;strcpy(server_address.sun_path, "server_socket");server_len = sizeof(server_address);bind(server_sockfd, (struct sockaddr *)&server_address, server_len);listen(server_sockfd, 5);printf("server waiting for  client connect\n");client_len = sizeof(client_address);//accept函数接收客户端求情,存储客户端地址信息、客户端地址大小client_sockfd = accept(server_sockfd,(struct sockaddr *)&client_address, (socklen_t *)&client_len);printf("the server wait form client data\n");for(i=0,ch_send=0;i<5;i++,ch_send++){//从client_sockfd读取客户端发来的消息if((byte=read(client_sockfd, recv_buf, sizeof(recv_buf)))==-1){perror("read");exit(EXIT_FAILURE);}printf("the massage receiver from client is: %s\n",recv_buf);sleep(1);//向客户端发送消息if((byte=write(client_sockfd,&ch_send,sizeof(ch_send)))==-1){perror("write");exit(EXIT_FAILURE);}}close(client_sockfd);unlink("server socket");exit(0);
}

client

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{int sockfd;int len;struct sockaddr_un address;int result;int i,byte;char send_buf[128];int ch_recv;if((sockfd = socket(AF_UNIX, SOCK_STREAM, 0))==-1)//创建socket,指定通信协议为AF_UNIX,数据方式SOCK_STREAM{perror("socket");exit(EXIT_FAILURE);}//配置server_addressaddress.sun_family = AF_UNIX;strcpy(address.sun_path, "server_socket");len = sizeof(address);result = connect(sockfd, (struct sockaddr *)&address, len);if(result == -1) {printf("ensure the server is up\n");perror("connect");exit(EXIT_FAILURE);}for(i=0;i<5;i++){sprintf(send_buf,"client massage %d",i);//用sprintf事先把消息写到send_bufif((byte=write(sockfd, send_buf, sizeof(send_buf)))==-1){perror("write");exit(EXIT_FAILURE);}if((byte=read(sockfd,&ch_recv,sizeof(ch_recv)))==-1){perror("read");exit(EXIT_FAILURE);}printf("receive from server data is: %d\n",ch_recv);}	close(sockfd);return 0;
}

结果

xili271948@er04180p:~/tcp$ ./uds_client 
receive from server data is: 0
receive from server data is: 1
receive from server data is: 2
receive from server data is: 3
receive from server data is: 4xili271948@er04180p:~/tcp$ ./uds_server 
server waiting for  client connect
the server wait form client data
the massage receiver from client is: client massage 0
the massage receiver from client is: client massage 1
the massage receiver from client is: client massage 2
the massage receiver from client is: client massage 3
the massage receiver from client is: client massage 4

这篇关于UNP——socket套接字分析以及IPC_UDS的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/454588

相关文章

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者

MOLE 2.5 分析分子通道和孔隙

软件介绍 生物大分子通道和孔隙在生物学中发挥着重要作用,例如在分子识别和酶底物特异性方面。 我们介绍了一种名为 MOLE 2.5 的高级软件工具,该工具旨在分析分子通道和孔隙。 与其他可用软件工具的基准测试表明,MOLE 2.5 相比更快、更强大、功能更丰富。作为一项新功能,MOLE 2.5 可以估算已识别通道的物理化学性质。 软件下载 https://pan.quark.cn/s/57

衡石分析平台使用手册-单机安装及启动

单机安装及启动​ 本文讲述如何在单机环境下进行 HENGSHI SENSE 安装的操作过程。 在安装前请确认网络环境,如果是隔离环境,无法连接互联网时,请先按照 离线环境安装依赖的指导进行依赖包的安装,然后按照本文的指导继续操作。如果网络环境可以连接互联网,请直接按照本文的指导进行安装。 准备工作​ 请参考安装环境文档准备安装环境。 配置用户与安装目录。 在操作前请检查您是否有 sud

线性因子模型 - 独立分量分析(ICA)篇

序言 线性因子模型是数据分析与机器学习中的一类重要模型,它们通过引入潜变量( latent variables \text{latent variables} latent variables)来更好地表征数据。其中,独立分量分析( ICA \text{ICA} ICA)作为线性因子模型的一种,以其独特的视角和广泛的应用领域而备受关注。 ICA \text{ICA} ICA旨在将观察到的复杂信号

【软考】希尔排序算法分析

目录 1. c代码2. 运行截图3. 运行解析 1. c代码 #include <stdio.h>#include <stdlib.h> void shellSort(int data[], int n){// 划分的数组,例如8个数则为[4, 2, 1]int *delta;int k;// i控制delta的轮次int i;// 临时变量,换值int temp;in

三相直流无刷电机(BLDC)控制算法实现:BLDC有感启动算法思路分析

一枚从事路径规划算法、运动控制算法、BLDC/FOC电机控制算法、工控、物联网工程师,爱吃土豆。如有需要技术交流或者需要方案帮助、需求:以下为联系方式—V 方案1:通过霍尔传感器IO中断触发换相 1.1 整体执行思路 霍尔传感器U、V、W三相通过IO+EXIT中断的方式进行霍尔传感器数据的读取。将IO口配置为上升沿+下降沿中断触发的方式。当霍尔传感器信号发生发生信号的变化就会触发中断在中断

kubelet组件的启动流程源码分析

概述 摘要: 本文将总结kubelet的作用以及原理,在有一定基础认识的前提下,通过阅读kubelet源码,对kubelet组件的启动流程进行分析。 正文 kubelet的作用 这里对kubelet的作用做一个简单总结。 节点管理 节点的注册 节点状态更新 容器管理(pod生命周期管理) 监听apiserver的容器事件 容器的创建、删除(CRI) 容器的网络的创建与删除

PostgreSQL核心功能特性与使用领域及场景分析

PostgreSQL有什么优点? 开源和免费 PostgreSQL是一个开源的数据库管理系统,可以免费使用和修改。这降低了企业的成本,并为开发者提供了一个活跃的社区和丰富的资源。 高度兼容 PostgreSQL支持多种操作系统(如Linux、Windows、macOS等)和编程语言(如C、C++、Java、Python、Ruby等),并提供了多种接口(如JDBC、ODBC、ADO.NET等

OpenCV结构分析与形状描述符(11)椭圆拟合函数fitEllipse()的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C++11 算法描述 围绕一组2D点拟合一个椭圆。 该函数计算出一个椭圆,该椭圆在最小二乘意义上最好地拟合一组2D点。它返回一个内切椭圆的旋转矩形。使用了由[90]描述的第一个算法。开发者应该注意,由于数据点靠近包含的 Mat 元素的边界,返回的椭圆/旋转矩形数据