CAN 通信原理学习

article/2025/8/30 1:18:58

文章目录

  • CAN通信
    • 一:基本概述
      • 1.1 can总线是什么
      • 1.2 can总线协议的特点
      • 1.3 can的网络通信结构
        • 1.3.1
        • 1.3.2 can协议网络层次
    • 二:socket can在通信网络中的应用
      • 三 一个程序

CAN通信

一:基本概述

1.1 can总线是什么

CAN 是 Controller Area Network 的缩写,是 ISO 国际标准化的串行通信协议。通俗来讲,CAN总线就是一种传输数据的线,用于在不同的ECU之间传输数据。
CAN(Controller Area Network)是ISO国际标准化的串行通信协议。广泛应用于汽车、船舶等。具有已经被大家认可的高性能和可靠性。
CAN控制器通过组成总线的2根线 (CAN-H和CAN-L)的电位差来确定总线的电平 ,在任一时刻,总线上有2种电平:显性电平和隐性电平。
“显性”具有“优先”的意味,只要有一个单元输出显性电平,总线上即为显性电平,并且,“隐性”具有“包容”的意味,只有所有的单元都输出隐性电平,总线上才为隐性电平。(显性电平比隐性电平更强)。
总线上执行逻辑上的线“与”时,显性电平的逻辑值为“0”,隐性电平为“1”。
下图显示了一个典型的CAN拓扑连接图。
在这里插入图片描述

连接在总线上的所有单元都能够发送信息,如果有超过一个单元在同一时刻发送信息,有最高优先级的单元获得发送的资格,所有其它单元执行接收操作。

can的拓扑结构:

在这里插入图片描述


1.2 can总线协议的特点

CAN总线协议具有下面的特点:

1) 多主控制

当总线空闲时,连接到总线上的所有单元都可以启动发送信息,这就是所谓的多主控制的概念。
先占有总线的设备获得在总线上进行发送信息的资格。这就是所谓的CSMA/CR(Carrier Sense MultipleAccess/Collosion Avoidance)方法
如果多个设备同时开始发送信息,那么发送最高优先级ID消息的设备获得发送资格。

2) 信息的发送

在CAN协议中,所有发送的信息要满足预先定义的格式。当总线没有被占用的时候,连接在总线上的任何设备都能起动新信息的传输,如果两个或更多个设备在同时刻启动信息的传输,通过ID来决定优先级。ID并不是指明信息发送的目的地,而是指示信息的优先级。如果2个或者更多的设备在同一时刻启动信息的传输,在总线上按照信息所包含的ID的每一位来竞争,赢得竞争的设备(也就是具有最高优先级的信息)能够继续发送,而失败者则立刻停止发送并进入接收操作。因为总线上同一时刻只可能有一个发送者,而其它均处于接收状态,所以,并不需要在底层协议中定义地址的概念。

3) 系统的灵活性

连接到总线上的单元并没有类似地址这样的标识,所以,添加或去除一个设备,无需改变软件和硬件,或其它设备的应用层软件。

4) 通信速度

可以设置任何通讯速度,以适应网络规模。
对一个网络,所有单元必须有相同的通讯速度,如果不同,就会产生错误,并妨碍网络通讯,然而,不同网络间可以有不同的通讯速度。

5) 远程数据请求

可以通过发送“遥控帧”,请求其他单元发送数据。

6) 错误检测、错误通知、错误恢复功能

所有单元均可以检测出错误(错误检测功能)。
检测到错误的单元立刻同时通知其它所有的单元(错误通知功能)。如果一个单元发送信息时检测到一个错误,它会强制终止信息传输,并通知其它所有设备发生了错误,然后它会重传直到信息正常传输出去(错误恢复功能)。

7) 错误隔离

在CAN总线上有两种类型的错误:暂时性的错误(总线上的数据由于受到噪声的影响而暂时出错);持续性的错误(由于设备内部出错(如驱动器坏了、连接有问题等)而导致的)。CAN能够区别这两种类型,一方面降低常出错单元的通讯优先级以阻止对其它正常设备的影响,另一方面,如果是一种持续性的错误,将这个设备从总线上隔离开。

8) 连接

CAN总线允许多个设备同时连接到总线上且在逻辑上没有数目上的限制。然而由于延迟和负载能力的限制,实际可连接得设备还是有限制的,可以通过降低通讯速度来增加连接的设备个数。相反,如果连接的设备少,通讯的速度可以增加。


1.3 can的网络通信结构

1.3.1

实际上,CAN总线网络底层只采用了OSI基本参照模型中的数据链路层、传输层。而在CAN网络高层仅采用了OSI基本参照模型的应用层
在这里插入图片描述


1.3.2 can协议网络层次

在CAN协议中,ISO标准只对数据链路层和物理层做了规定。对于数据链路层和物理层的一部分,ISO11898和ISO11519-2的规定是相同,但是在物理层的PMD子层和MDI子层是不同的。
在这里插入图片描述

在CAN总线,每一层网络中定义的事项如下:
在这里插入图片描述


二:socket can在通信网络中的应用

socket can应用实例
server端:

#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
int can_recv() {int sock_fd;unsigned long nbytes, len;struct sockaddr_can addr;struct ifreq ifr;/*为了能够接收CAN报文,我们需要定义一个CAN数据格式的结构体变量*/struct can_frame frame;struct can_frame *ptr_frame;/* 建立套接字,设置为原始套接字,原始CAN协议 */sock_fd = socket(PF_CAN, SOCK_RAW, CAN_RAW);/* 对CAN接口进行初始化,设置CAN接口名,即当我们用ifconfig命令时显示的名字 */strcpy(ifr.ifr_name, "can0");ioctl(sock_fd, SIOCGIFINDEX, &ifr);/*设置CAN协议 */addr.can_family = AF_CAN;addr.can_ifindex = 0;/*将刚生成的套接字与网络地址进行绑定*/bind(sock_fd, (struct sockaddr *)&addr, sizeof(addr));/*开始接收数据*/nbytes = recvfrom(sock_fd, &frame, sizeof(struct can_frame), 0,(struct sockaddr *)&addr, (socklen_t *)&len);/*get interface name of the received CAN frame*/ifr.ifr_ifindex = addr.can_ifindex;ioctl(sock_fd, SIOCGIFNAME, &ifr);printf("Received a CAN frame from interface %s\n", ifr.ifr_name);/*将接收到的CAN数据打印出来,其中ID为标识符,DLC为CAN的字节数,DATA为1帧报文的字节数*/printf("CAN frame:\nID = %x\nDLC = %x\nDATA = %s\n", frame.can_id,frame.can_dlc, frame.data);ptr_frame = &frame;return 0;
}

client

#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
int can_send() {int sock_fd;unsigned long nbytes;struct sockaddr_can addr;struct ifreq ifr;struct can_frame frame;/*建立套接字,设置为原始套接字,原始CAN协议 */sock_fd = socket(PF_CAN, SOCK_RAW, CAN_RAW);/* 对CAN接口进行初始化,设置CAN接口名,即当我们用ifconfig命令时显示的名字 */strcpy((char *)(ifr.ifr_name), "can0");ioctl(sock_fd, SIOCGIFINDEX, &ifr);printf("can0 can_ifindex = %x\n", ifr.ifr_ifindex);addr.can_family = AF_CAN;addr.can_ifindex = ifr.ifr_ifindex;/*将刚生成的套接字与CAN套接字地址进行绑定*/bind(sock_fd, (struct sockaddr *)&addr, sizeof(addr));/*设置CAN帧的ID号,可区分为标准帧和扩展帧的ID号*/frame.can_id = 0x1122;strcpy((char *)frame.data, "hello");frame.can_dlc = strlen((char *)frame.data);printf("Send a CAN frame from interface %s\n", ifr.ifr_name);/*开始发送数据*/nbytes = sendto(sock_fd, &frame, sizeof(struct can_frame), 0,(struct sockaddr *)&addr, sizeof(addr));return 0;
}

上面两个程序看完后,大家可能会有疑问,为什么这两个程序没有listen()和accept()函数呢?
其实这两个程序是独立的运行的,并不像字节流套接字(SOCK_STREAM)和数据报套接字(SOCK_DGRAM),需要先运行服务器进行侦听。SOCK_STREAM和SOCK_DGRAM的两个server和client程序是通过网络相互收发数据。
而CAN的socket的server和client程序收发数据的对象是CAN总线。server从CAN总线上接收数据,client将数据发到CAN总线上,当CAN总线上有数据时,server才能接收数据,当CAN总线空闲时,client才能将数据发送出去。


三 一个程序

近写了个自认为不错的基于linux socket can程序,主要功能:

1.程序具备全部CAN功能,包括CAN标准帧/扩展帧接收与发送、CAN总线错误判断、环回等功能
2.适用基于LINUX SOCKET机制实现的CAN接口,可用于嵌入式LINUX的CAN测试
3.程序采用标准LINUX命令行参数选项形式,接受用户参数

int main(int argc, char **argv)
{S_CanFrame sendframe, recvframe;byte *psendframe = (byte *)&sendframe;byte *precvframe = (byte *)&recvframe;u_canframe_data_t *psend_data = (u_canframe_data_t *)sendframe.data;const int can_frame_len = sizeof(S_CanFrame); pid_t pid = -1;int   status;int  ret = 0;char buf[128] = {0};bool carry_bit = false;// 进位标志int segment_id;//id for shared memoif (parse_options(argc, argv)){usage();    return  0;}if (!find_can(port)){sprintf(buf, "\n\t错误:CAN%d设备不存在\n\n", port + 1);panic(buf);return  -1;}close_can(port);// 必须先关闭CAN,才能成功设置CAN波特率set_bitrate(port, bitrate);// 操作CAN之前,先要设置波特率open_can(port, bitrate);send_socket_fd = socket_connect(port);recv_socket_fd = socket_connect(port);//printf("send_socket_fd = %d, recv_socket_fd = %d\n", send_socket_fd, recv_socket_fd);if (send_socket_fd < 0 || send_socket_fd < 0){disconnect(&send_socket_fd);disconnect(&recv_socket_fd);panic("\n\t打开socket can错误\n\n");return  -1;}set_can_filter();set_can_loopback(send_socket_fd, lp);printf_head();memset(&sendframe, 0x00, sizeof(sendframe));memset(&recvframe, 0x00, sizeof(recvframe));if (extended_frame) // 指定发送帧类型:扩展帧或标准帧{sendframe.can_id = (send_frame_id & CAN_EFF_MASK) | CAN_EFF_FLAG;} else{sendframe.can_id = (send_frame_id & CAN_SFF_MASK);}sendframe.can_dlc = dlc;memcpy(sendframe.data, send_frame_data, dlc);segment_id = shmget(IPC_PRIVATE, sizeof(int), S_IRUSR | S_IWUSR);// allocate memopframeno = (int *)shmat(segment_id, NULL, 0);// attach the memoif (pframeno == NULL){panic("\n\t创建共享内存失败\n\n");return  -1;}*pframeno = 1;run = true;pid = fork();if(pid == -1) { panic("\n\t创建进程失败\n\n");return  -1;}else if(pid == 0) // 子进程,用于发送CAN帧{while (run && (send_frame_times > 0)){ret = send_frame(send_socket_fd, (char *)&sendframe, sizeof(sendframe));printf_frame(sendframe.can_id & CAN_EFF_MASK, sendframe.data, sendframe.can_dlc, ((sendframe.can_id & CAN_EFF_FLAG) ? true : false),ret > 0 ? true : false, true);delay_ms(send_frame_freq_ms);if (send_frame_id_inc_en){sendframe.can_id++;if (extended_frame){sendframe.can_id = (sendframe.can_id & CAN_EFF_MASK) | CAN_EFF_FLAG;} else{sendframe.can_id = (sendframe.can_id & CAN_SFF_MASK);}}if (send_frame_data_inc_en && dlc > 0){if (dlc > 4 && psend_data->s.dl == ((__u32)0xFFFFFFFF)){carry_bit = true;// 发生进位}psend_data->s.dl++;if (dlc <= 4){if (psend_data->s.dl >= (1 << (dlc * 8))){psend_data->s.dl = 0;}}else if (dlc <= 8){if (carry_bit){psend_data->s.dh++;if (psend_data->s.dh >= (1 << ((dlc - 4) * 8))){psend_data->s.dh = 0;}carry_bit = false;}}}send_frame_times--;}exit(0);}else // 父进程,接收CAN帧{install_sig();while (run){memset(precvframe, 0x00, can_frame_len);ret = recv_frame(recv_socket_fd, precvframe, can_frame_len, 5 * 1000);if (ret > 0){printf_frame(recvframe.can_id & CAN_EFF_MASK, recvframe.data, recvframe.can_dlc, ((recvframe.can_id & CAN_EFF_FLAG) ? true : false),true, false);}}while(((pid = wait(&status)) == -1) && (errno == EINTR)){delay_ms(10);}}disconnect(&send_socket_fd);disconnect(&recv_socket_fd);shmdt(pframeno);// detach memoshmctl(segment_id, IPC_RMID, NULL);// removereturn  0;
}

http://chatgpt.dhexx.cn/article/NUja3EnZ.shtml

相关文章

CAN通信协议

在 CAN 协议中&#xff0c;所有的消息都以固定的格式发送。总线空闲时&#xff0c;所有与总线相连的单元都可以开始发送新消息。两个以上的单元同时开始发送消息时&#xff0c;根据标识符&#xff08;Identifier 以下称为 ID&#xff09;决定优先级。ID 并不是表示发送的目的地…

CAN通信讲解(1)——基本知识

本文注意参考了《CAN入门书》&#xff0c;源于此书图片不再特殊标注 目录 1.1 CAN总线背景1.2 CAN总线定义1.3 CAN总线信号特性1.4 CAN总线传输1.5 OSI基本参照模型和CAN总线协议 1.1 CAN总线背景 为减少汽车线束数量&#xff0c;1986年&#xff0c;博世开发出面向汽车的CAN通…

CAN通信

通讯方式 UART&#xff1a;(Universal Asynchronous Receiver Transmitter&#xff1a;通用异步收发器/异步串行通信口)&#xff0c;是一种通用的串行数据总线&#xff0c;用于异步通信&#xff0c;支持全双工。它包括了RS232、RS499、RS423、RS422和RS485等接口标准规范和总线…

CAN通信----基本原理

STM32标准库开发 文章链接&#xff1a; STM32F103标准库开发----目录 STM32F103标准库开发----CAN总线通信实验----初始化/波特率 STM32F103标准库开发----CAN总线通信实验----发送和接收 资源链接&#xff1a; 本例程已经调试成功&#xff0c;下载即可使用。 STM32F103标准库…

CAN通信详解(全)

本章我们将向大家介绍如何使用STM32自带的CAN控制器来实现两个开发板之间的CAN通讯&#xff0c;并将结果显示在TFTLCD模块上。本章分为如下几个部分&#xff1a; 30.1 CAN简介 30.2 硬件设计 30.3 软件设计 30.4 下载验证 30.1 CAN简介 CAN 是Controller Area Network 的缩…

Tomcat优化禁用AJP协议

登录tomcat 在服务状态页面中可以看到&#xff0c;默认状态下会启用AJP服务&#xff0c;并且占用8009端口。 什么是AJP呢&#xff1f; AJP&#xff08;Apache JServer Protocol&#xff09; AJPv13协议是面向包的。WEB服务器和Servlet容器通过TCP连接来交互&#xff1b;为了…

tomcat启动出现错误:Failed to destroy end point associated with ProtocolHandler[“ajp-nio-8009“](解决非常简单)

tomcat启跑不起来而且报了很多莫名其妙的错误不知道从哪里找起 启动服务器出现这个错误 console提示&#xff1a;Failed to destroy end point associated with ProtocolHandler[“ajp-nio-8009”] 直接看web.xml的url-pattern这个属性是不是哪一个少了‘/’ 或者 如果没有…

Java安全-Tomcat AJP 文件包含漏洞(CVE-2020-1938)幽灵猫漏洞复现

Tomcat AJP 文件包含漏洞&#xff08;CVE-2020-1938&#xff09; CVE-2020-1938 又名GhostCat ApacheTomcat服务器中被发现存在文件包含漏洞&#xff0c;攻击者可利用该漏洞读取或包含Tomcat 上所有 webapp 目录下的任意文件 该漏洞是一个单独的文件包含漏洞&#xff0c;依赖…

Aapache Tomcat AJP 文件包含漏洞-(CVE-2020-1938/CNVD-2020-10487)

漏洞编号 CVE-2020-1938 CNVD-2020-10487 靶机环境 Vulhub虚拟靶场 vulhub-master/tomcat/CVE-2020-1938 启动docker&#xff1a; 启动成功&#xff1a; 0x00 漏洞简介 2月20日&#xff0c;国家信息安全漏洞共享平台&#xff08;CNVD&#xff09;发布了Apache Tomcat文件包含漏…

Apache-Tomcat-Ajp漏洞测试与修复

说明 Apache Tomcat会开启AJP连接器,方便与其他Web服务器通过AJP协议进行交互。由于Tomcat本身也内含了HTTP服务器&#xff0c;因此也可以视作单独的Web服务器。此漏洞为文件包含漏洞&#xff0c;攻击者可利用该漏洞读取或包含 Tomcat 上所有 webapp 目录下的任意文件&#xf…

解决AJP漏洞操作记录

前言 最近Tomcat爆出AJP漏洞&#xff0c;升级对应版本的Tomcat是比较好的规避方法。本文将记录笔者在升级Tomcat 9.0.31时踩过的一些坑&#xff0c;以便大家能快速升级Tomcat。 本文只针对Tomcat 9.0.31版本的操作记录。 Tomcat受影响版本&#xff1a; Apache Tomcat 9.x &l…

tomcat中ajp及8009端口用处

tomcat常用于提供servlet/jsp容器服务&#xff0c;简单方便、使用高效。但是tomcat处理静态文件资源的性能不足&#xff08;应该是serviece部分&#xff09;&#xff0c;同时&#xff0c;如果用户直接与tomcat进行http的连接获取静态资源&#xff08;连接器connector部分&#…

CVE-2020-1938 :Apache Tomcat AJP 漏洞复现和分析

一、漏洞描述 Apache Tomcat是由Apache软件基金会属下Jakarta项目开发的Servlet容器.默认情况下,Apache Tomcat会开启AJP连接器,方便与其他Web服务器通过AJP协议进行交互.但Apache Tomcat在AJP协议的实现上存在漏洞,导致攻击者可以通过发送恶意的AJP请求,可以读取或者包含Web应…

网络抓包方式复现Tomcat- AJP协议文件读取/命令执行漏洞(CVE-2020-1938 / CNVD-2020-10487)

目录 测试是否安装成功​编辑 基础简介 Tomcat Connector(连接器) ​编辑Servlet(服务程序) Tomcat内部处理请求流程 文件读取漏洞 抓包复现 需要将下图中抓取到的数据包修改一下 ​编辑 替换成二进制数据的形式&#xff1a; 运行结果 ​编辑 创建脚本文件&#xf…

AJP协议

由于tomcat的html和图片解析功能相对其他服务器如apche等较弱&#xff0c;所以&#xff0c;一般都是集成起来使用&#xff0c;只有jsp和servlet服务交由tomcat处理&#xff0c;而tomcat和其他服务器的集成&#xff0c;就是通过ajp协议来完成的。AJP协议AJP13是定向包协议。因为…

Apache Tomcat AJP协议文件读取与包含

永远也不要忘记能够笑的坚强&#xff0c;就算受伤&#xff0c;我也从不彷徨。 0x01.漏洞情况分析 Tomcat是Apache软件基金会Jakarta 项目中的一个核心项目&#xff0c;作为目前比较流行的Web应用服务器&#xff0c;深受Java爱好者的喜爱&#xff0c;并得到了部分软件开发商的…

Tomcat AJP 文件包含漏洞(CVE-2020-1938)

目录 1&#xff0e;漏洞简介 2、AJP13 协议介绍 Tomcat 主要有两大功能&#xff1a; 3&#xff0e;Tomcat 远程文件包含漏洞分析 4&#xff0e;漏洞复现 5、漏洞分析 6&#xff0e;RCE 实现的原理 1&#xff0e;漏洞简介 2020 年 2 月 20 日&#xff0c;公开CNVD 的漏洞公…

Tomcat HTTP协议与AJP协议

https://blog.csdn.net/jeikerxiao/article/details/82745516 Tomcat HTTP协议与AJP协议 HTTP Connector AJP Connector 配置 Tomcat在server.xml中配置了两种连接器。 HTTP Connector 拥有这个连接器&#xff0c;Tomcat才能成为一个web服务器&#xff0c;但还额外可处理Serv…

Tomcat架构解析之AJP

一、前言 除了HTTP&#xff0c;Tomcat还支持AJP协议&#xff0c;以便于Apache HTTP Server等Web服务器集成&#xff0c;这篇博客主要讲解AJP协议的基础知识以及其配置使用方式。 二、基础知识 为了满足负载均衡、静态资源优化、遗留系统集成&#xff08;如集成PHP Web应用&…

HTTP协议与AJP协议

AJP 全称 Apache JServ Protocol&#xff0c; 是定向包协议&#xff0c;因为性能的原因&#xff0c;使用二进制格式来传输可读性文本&#xff0c;WEB服务器通过TCP连接和SERVLET容器连接。 一旦WEB服务器打开了一个到SERVLET容器的连接&#xff0c;连接处于下面的状态&#xff…