socketcan

2023-05-16

参考<<Linux_Can编程详解>>
CAN原理介绍: https://www.cnblogs.com/spoorer/p/6649303.html

一.初始化工作

SocketCAN 中大部分的数据结构和函数在头文件 linux/can.h 中进行了定义。 
CAN 总线套接字的
创建采用标准的网络套接字操作来完成。网络套接字在头文件 sys/socket.h 中定义。

套接字的初始化方法如下:

int s;//类似于socket_fd

struct sockaddr_can addr;
struct ifreq ifr;
s = socket(PF_CAN, SOCK_RAW, CAN_RAW);     //创建 SocketCAN 套接字
strcpy(ifr.ifr_name, "can0" );             //can0是ifconfig看到的,也可能是其他名字
ioctl(s, SIOCGIFINDEX, &ifr);              //指定 can0 设备
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
bind(s, (struct sockaddr *)&addr, sizeof(addr)); //将套接字与 can0 绑定

我在机器上ubuntu 16.04装了一个虚拟的can,名字为vcan,具体指令如下:

sudo ip link add dev vcan0 type vcan
sudo ip link set dev vcan0 down
sudo ip link set vcan0 mtu 72 
sudo ip link set dev vcan0 up
ifconfig

二.数据发送

在数据收发的内容方面, CAN 总线与标准套接字通信稍有不同,每一次通信都采用 can_ frame 结
构体将数据封装成帧。结构体定义如下:
struct can_frame {
canid_t  can_id;//CAN 标识符
__u8 can_dlc;//数据场的长度
__u8 data[8];//数据
};

can_id 为帧的标识符,如果发出的是标准帧,就使用 can_id 的低 11 位;
如果为扩展帧,就使用 0~ 28 位。 can_id 的第 29 、 30 、 31 位是帧的标志位,用来定义帧的类型,
定义如下:#define CAN_EFF_FLAG 0x80000000U //扩展帧的标识
#define CAN_RTR_FLAG 0x40000000U         //远程帧的标识
#define CAN_ERR_FLAG 0x20000000U         //错误帧的标识,用于错误检查


数据发送使用 write 函数来实现。
如果发送的数据帧 ( 标识符为 0x123) 包含单个字节 (0xAB) 的数据,可采用如下方法进行发送:

struct can_frame frame;  //定义数据结构体变量
frame.can_id = 0x123;    //如果为扩展帧,那么 frame.can_id = CAN_EFF_FLAG | 0x123;
frame.can_dlc = 1;       //数据长度为 1
frame.data[0] = 0xAB;    //数据内容为 0xAB

int nbytes = write(s, &frame, sizeof(frame)); //发送数据
//发送数据即就是给对应的fd上写数据,内容为frame,大小为sizeof(freme),与网络 socket一样的
if(nbytes != sizeof(frame))     //如果 nbytes 不等于帧长度,就说明发送失败
printf("Error\n!"); 



如果要发送远程帧 ( 标识符为 0x123) ,可采用如下方法进行发送:
struct can_frame frame;
frame.can_id = CAN_RTR_FLAG | 0x123;
write(s, &frame, sizeof(frame));

3.数据的接受

数据接收使用 read 函数来完成,实现如下:

//需要定义同样的一个数据结构体,因为所有传输的数据
struct can_frame frame;
int nbytes = read(s, &frame, sizeof(frame));
//同样的,从socketfd中读取数据,该数据也还是要写入相同的结构体中的

当然,套接字数据收发时常用的 send 、 sendto 、 sendmsg 以及对应的 recv 函数也都可以用于 CAN
总线数据的收发,因为底层都是调用sys_read  实际上所有操作被抽象为文件的读写

4.错误处理

当帧接收后,可以通过判断 can_id 中的 CAN_ERR_FLAG 位来判断接收的帧是否为错误帧。

如果为错误帧,可以通过 can_id 的其他符号位来判断错误的具体原因。
错误帧的符号位在头文件 linux/can/error.h 中定义。

5.数据过滤

在数据接收时,系统可以根据预先设置的过滤规则,实现对报文的过滤。
过滤规则使用 can_filter 结构体
来实现,定义如下:
struct can_filter {
canid_t can_id;
canid_t can_mask;};

过滤的规则为:
接收到的数据帧的 can_id &mask == 本地设置过滤规则中的 can_id & mask

通过这条规则可以在系统中过滤掉所有不符合规则的报文,使得应用程序不需要对无关的报文进行
处理。在 can_filter 结构的 can_id 中,符号位 CAN_INV_FILTER 在置位时可以实现 can_id 在执行过
滤前的位反转。
用户可以为每个打开的套接字设置多条独立的过滤规则,使用方法如下:
struct can_filter rfilter[2];
rfilter[0].can_id
= 0x123;
rfilter[0].can_mask = CAN_SFF_MASK; //#define CAN_SFF_MASK 0x000007FFU
rfilter[1].can_id
= 0x200;
rfilter[1].can_mask = 0x700;
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));//设置规则
在极端情况下,如果应用程序不需要接收报文,可以禁用过滤规则。这样的话,原始套接字就会忽略所有
接收到的报文。在这种仅仅发送数据的应用中,可以在内核中省略接收队列,以此减少 CPU 资源的消耗。禁
用方法如下:
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0); //禁用过滤规则
通过错误掩码可以实现对错误帧的过滤,例如:
can_err_mask_t err_mask = ( CAN_ERR_TX_TIMEOUT | CAN_ERR_BUSOFF );
setsockopt(s, SOL_CAN_RAW, CAN_RAW_ERR_FILTER, err_mask, sizeof(err_mask));
在默认情况下,本地回环功能是开启的,可以使用下面的方法关闭回环 / 开启功能:
int loopback = 0; // 0 表示关闭, 1 表示开启(默认)
setsockopt(s, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback, sizeof(loopback));
在本地回环功能开启的情况下,所有的发送帧都会被回环到与 CAN 总线接口对应的套接字上。默认情况
下,发送 CAN 报文的套接字不想接收自己发送的报文,因此发送套接字上的回环功能是关闭的。可以在
需要的时候改变这一默认行为:
int ro = 1; // 0 表示关闭(默认), 1 表示开启
setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, &ro, sizeof(ro));

源程序:

//发送数据
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
int main()
{
	int s, nbytes;
	struct sockaddr_can addr;
	struct ifreq ifr;
	struct can_frame frame[2] = {{0}};
	s = socket(PF_CAN, SOCK_RAW, CAN_RAW);//创建套接字
	strcpy(ifr.ifr_name, "vcan0" );
	ioctl(s, SIOCGIFINDEX, &ifr); //指定 can0 设备
	addr.can_family = AF_CAN;
	addr.can_ifindex = ifr.ifr_ifindex;
	bind(s, (struct sockaddr *)&addr, sizeof(addr));//将套接字与 can0 绑定
	//禁用过滤规则,本进程不接收报文,只负责发送
	setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
	//生成两个报文
	frame[0].can_id = 0x11;
	frame[0]. can_dlc = 1;
	frame[0].data[0] = 'Y';
	frame[0].can_id = 0x22;
	frame[0]. can_dlc = 1;
	frame[0].data[0] = 'N';//循环发送两个报文
	while(1)
	{
		nbytes = write(s, &frame[0], sizeof(frame[0]));
		//发送 frame[0]
		if(nbytes != sizeof(frame[0]))
		{
			printf("Send Error frame[0]\n!");
			break; //发送错误,退出
		}
		sleep(1);
		nbytes = write(s, &frame[1], sizeof(frame[1]));
		if(nbytes != sizeof(frame[0]))
		{
			printf("Send Error frame[1]\n!");
			break;
		}
	sleep(1);
	}

	close(s);
	return 0;
}

//接收数据
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
int main()
{
	int s, nbytes;
	struct sockaddr_can addr;
	struct ifreq ifr;
	struct can_frame frame;
	struct can_filter rfilter[1];
	s = socket(PF_CAN, SOCK_RAW, CAN_RAW); //创建套接字
	strcpy(ifr.ifr_name, "vcan0" );
	ioctl(s, SIOCGIFINDEX, &ifr); //指定 can0 设备
	addr.can_family = AF_CAN;
	addr.can_ifindex = ifr.ifr_ifindex;
	bind(s, (struct sockaddr *)&addr, sizeof(addr)); //将套接字与 can0 绑定
	//定义接收规则,只接收表示符等于 0x11 的报文
	rfilter[0].can_id= 0x11;
	rfilter[0].can_mask = CAN_SFF_MASK;
	//设置过滤规则
	setsockopt(s,SOL_CAN_RAW,CAN_RAW_FILTER,&rfilter,sizeof(rfilter));
	while(1)
	{
		nbytes = read(s,&frame,sizeof(frame));
		//接收报文//显示报文
		if(nbytes > 0)
		{
			printf("ID=0x%x DLC=%d data[0]=0x%x\n",frame.can_id,frame.can_dlc,frame.data[0]);
		}
	}

	close(s);
	return 0;
}

用C++实现一个SocketCan的通信:

**头文件:**
#pragma once
#include <iostream>
#include <sys/socket.h>
#include <ney/if.h>
#include <sys/ioctl.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <unistd.h>

class SocketCan {
public:
  SocketCan();
  ~SocketCan();
  bool Read();
  bool Write();

private:
  int sockfd_;
  bool ready_;
  
private:
  int Connect();
  void DisConnect();
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

socketcan 的相关文章

  • 深入剖析PE文件 (告诉你exe文件打开后是依据什么来创建进程并在系统中运行)

    转自 深入剖析PE文件 告诉你exe文件打开后是依据什么来创建进程并在系统中运行 转载自http lwglucky blog 51cto com 1228348 283812 PE文件是Win32的原生文件格式 每一个Win32可执行文件都
  • 串口和TCP互相转发工具

    由于项目调试需求 xff0c 代码在远程服务器的虚拟机上 xff0c 在本地计算机通过串口连接需要对接的设备 xff0c 在远程服务器的上位机程序需要和此设备进行对接 xff0c 系统结构如图1所示 图1 系统网络结构图 如何将本地的串口共
  • Linux系统基础操作管理

    一 系统基础操作规范 1 第一个规范 输出命令信息需要在命令提示符之后输入 命令提示符 xff1a span class token punctuation span root 64 oldboy span class token punc
  • 解决Flask跨域问题的几种方式

    本文收录于 Python开发 专栏 xff0c 此专栏聚焦于Python开发中的编程技巧和总结 xff0c 将持续更新 xff0c 欢迎大家订阅 xff01 个人主页 xff1a 有梦想的程序星空个人介绍 xff1a 小编是人工智能领域硕士
  • STL四种智能指针浅析

    我们知道 xff0c 在C 43 43 中没有像Java那样的自动回收垃圾机制 xff0c xff0c 系统只会清理栈上由系统管理的资源 xff0c 在类中若有对堆资源的申请 xff0c 不进行手动释放资源就会导致内存泄漏问题 xff0c
  • C++摸板类 声明对象编译不过 类声明和实现都要放在头文件里

    通常情况下 xff0c 你会在 h文件中声明函数和类 xff0c 而将它们的定义放置在一个单独的 cpp文件中 但是在使用模板时 xff0c 这种习惯性做法将变得不再有用 xff0c 因为当实例化一个模板时 xff0c 编译器必须看到模板确
  • 什么是大端序和小端序,为什么要有字节序

    什么是字节序 字节序 xff0c 又称端序或尾序 xff08 英语中用单词 xff1a Endianness 表示 xff09 xff0c 在计算机领域中 xff0c 指电脑内存中或在数字通信链路中 xff0c 占用多个字节的数据的字节排列
  • opencv4.3.0+Visual Studio 2019环境配置

    1 1 解压opencv并添加环境变量 下载opencv4 3 0 xff0c 进行安装 其实是解压 xff0c 之后配置环境变量 xff0c 我的电脑 gt 属性 gt 高级系统设置 gt 环境变量 xff0c 找到Path变量 xff0
  • 动画图解:十大经典排序算法动画与解析,看我就够了!(配代码完全版)

    排序算法是 数据结构与算法 中最基本的算法之一 排序算法可以分为内部排序和外部排序 内部排序是数据记录在内存中进行排序 而外部排序是因排序的数据很大 xff0c 一次不能容纳全部的排序记录 xff0c 在排序过程中需要访问外存 常见的内部排

随机推荐

  • 什么是 P = NP 问题?

    点击关注上方 五分钟学算法 xff0c 设为 置顶或星标 xff0c 第一时间送达干货 转自后端技术指南针 1 前言 今天和大家一起了解个高能知识点 xff1a P 61 NP问题 看到这里我们可能是一头雾水 xff0c 不由得发问 xff
  • 问题集合 ---- linux 静态库和动态库

    本文转自多网址 xff0c 对作者表示感谢 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
  • 图解:什么是二叉排序树?

    点击关注上方 五分钟学算法 xff0c 设为 置顶或星标 xff0c 第一时间送达干货 转自景禹 景禹的写作风格还是一如既往的细腻 xff1a xff09 xff0c 欢迎关注他 以下为原文 今天我们谈一谈 二叉排序树 xff0c 一种你会
  • B 站疯传,堪称最强,10 大免费的白嫖网站

    点击上方 五分钟学算法 xff0c 选择 星标 公众号 重磅干货 xff0c 第一时间送达 来源 xff1a Python知识圈 如果你喜欢在 B 站学习的话 xff0c 可以经常看到一些介绍网站类的视频 xff0c 这些视频有不俗的播放量
  • 还敢搞黄色?4 个色情网站被一锅端,9 名福利姬被刑拘!

    点击上方 五分钟学算法 xff0c 选择 星标 公众号 重磅干货 xff0c 第一时间送达 来源 xff1a 扩展迷EXTFANS 9月4日 xff0c 据 64 江苏网警 通报 xff1a 今年3月份以来 xff0c 浙江丽水莲都警方根据
  • 为什么有人劝别选计算机专业?

    大家好 xff0c 我是程序员吴师兄 xff0c 一个坚持在 CSDN 日更原创的程序员 今天想和大家聊一聊为什么有人劝别选计算机专业 和大家说一句掏心窝的话 xff1a 直到 2021 年 xff0c 计算机专业依旧是寒门改变命运的一个最
  • 看完谷歌大佬的 LeetCode 刷题笔记,我马上去字节跳动面试!

    如果你刷 LeetCode 觉得吃力 那么一定需要这份谷歌大佬的 LeetCode 刷题笔记 微信搜索 五分钟学算法 xff0c 公众号回复 04 即可获取对应的下载链接 xff0c 以下是详细介绍 在这里推荐一个谷歌大佬的刷题笔记 每一道
  • 剑指 Offer 09. 用两个栈实现队列(视频讲解)

    一 题目描述 用两个栈实现一个队列 队列的声明如下 xff0c 请实现它的两个函数 appendTail 和 deleteHead xff0c 分别完成在队列尾部插入整数和在队列头部删除整数的功能 若队列中没有元素 xff0c delete
  • 刷到 LeetCode 这个评论,被笑到了

    大家好 xff0c 我是吴师兄 今天早上我在 LeetCode 第 141 号问题 环形链表 的评论区中发现了一个称得上是天秀的解法 xff0c 简直太骚气了 xff0c 忍不住分享给大家 首先给没有见过这道题目的小伙伴补充一下前置知识 x
  • Android JNI基础篇(一)

    Android JNI 基础篇 前言 JNI学习其实并不难 xff0c 在这里 xff0c 我将引导大家学习JNI的基础知识 xff0c 认真学完本教程 xff0c 你将更加坚信我说的话 来吧 xff0c 我们一起学习 xff01 JNI
  • ROS学习(三):消息通信过程

    主节点管理节点信息 xff0c 每个节点根据需要与其他节点进行连接和消息通信 在这里 xff0c 我们来看看最重要的主节点 节点 话题 服务和动作信息的过程 一 运行主节点 节点之间的消息通信当中 xff0c 管理连接信息的主节点是为使用R
  • HTTP Digest authentication(摘要认证)和HTTP basic Authorization(普通认证)用户登出注销的方法

    最近项目中需要对普通认证HTTP basic Authorization和摘要认证HTTP Digest authenticatio登录进行注销 搜索到有几篇文章号称ie xff0c Firefox chrome都可以可以注销 xff0c
  • POCO C++库学习和分析 -- 序

    POCO C 43 43 库学习和分析 序 1 POCO库概述 xff1a POCO是一个C 43 43 的开源库集 同一般的C 43 43 库相比 xff0c POCO的特点是提供了整一个应用框架 如果要做C 43 43 程序应用框架的快
  • 【ubuntu18+QT12+OpenCV4环境配置】

    ubuntu18 43 QT12 43 OpenCV4环境配置 前些天编译了最新版本opencv4 xff0c 但是电脑内还有个opencv3 2 xff0c 有时候二者共享链接库文件即libopencv so XX xff0c 之类的路径
  • Ubuntu无法使用浏览器上网

    1 可以更新一下浏览器 xff0c 打开终端 xff0c 输入 xff1a sudo apt get install firefox 如果你用的是其他浏览器可以吧后面的 firefox 改为其他浏览器 xff0c 如谷歌浏览器 xff1a
  • 浅析C++中struct和class的区别

    文章目录 C和C 43 43 中struct的区别C 43 43 中struct和class的区别 C和C 43 43 中struct的区别 struct最早是在C语言中出现的 xff0c 但在C语言中struct只是一种 用户自定义数据类
  • C语言头文件.h互相包含所引发的一系列错误C2143之类的解决方法

    本文可解决的问题 在一个头文件 h中定义一个结构体 在另一个 h文件中使用这个结构体引发错误C2143 语法错误 缺少 在 的前面 编译源文件 等莫名的报错头文件的交叉包含 即头文件a包含了头文件b 头文件b又包含了头文件a多个不同的头文件
  • 使用python进行http请求自动登录处理302跳转的问题

    一 问题背景 最近在做一个自动化业务处理的程序时 xff0c 需要完成对系统的自动登录 经过抓包测试只需要使用简单的post请求后收到的回包中包含cookie信息 xff0c 因此可以据此完成登录 程序设计思路为发送求到登录验证页面 xff
  • C# TCP/UDP网络通讯调试助手(含源码)

    C TCP UDP网络通讯调试助手 1 客户端界面 1 客户端界面 源码下载地址 xff1a https download csdn net download kingleitao 11927885
  • socketcan

    参考 lt lt Linux Can编程详解 gt gt CAN原理介绍 https www cnblogs com spoorer p 6649303 html 一 初始化工作 SocketCAN 中大部分的数据结构和函数在头文件 lin