对Socket CAN的理解(3)——【Socket CAN发送数据流程】

2023-05-16

转载请注明出处:http://blog.csdn.net/Righthek 谢谢!

    对于本文,我们将从用户层使用Socket CAN进行数据发送时,数据从用户空间到底层驱动的整个通信流程,用户层使用Socket CAN可参考上一篇文章《对Socket CAN的理解(2)——【Socket的原理及使用】》。

    当我们在用户层通过socket进行CAN数据的发送时,需要进行以下操作:

    (1) 创建一个套接字socket,采用AF_CAN协议;

    (2)将创建的套接字返回描述符sockfd,绑定到本地的地址;

    (3)通过sendto系统调用函数进行发送;

sendto的函数声明如下:

int sendto(int sockfd, const void *msg, intlen,unsigned intflags, const struct sockaddr *to, int tolen);

         主要参数说明如下:

         sockfd:通过socket函数生成的套接字描述符;

         msg:该指针指向需要发送数据的缓冲区;

         len:是发送数据的长度;

         to:目标主机的IP地址及端口号信息;

 

    sendto的系统调用会发送一帧数据报到指定的地址,在CAN协议调用之前把该地址移到内核空间和检查用户空间数据域是否可读。

在net/socket.c源文件中,sendto函数的系统调用如下代码:

SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len, unsigned, flags, structsockaddr __user *, addr, int, addr_len)

{

         structsocket *sock;

         structsockaddr_storage address;

         interr;

         structmsghdr msg;

         structiovec iov;

         intfput_needed;

         if(len > INT_MAX)

                   len= INT_MAX;

         sock= sockfd_lookup_light(fd, &err, &fput_needed);

         if(!sock)

                   gotoout;

         iov.iov_base= buff;

         iov.iov_len= len;

         msg.msg_name= NULL;

         msg.msg_iov= &iov;

         msg.msg_iovlen= 1;

         msg.msg_control= NULL;

         msg.msg_controllen= 0;

         msg.msg_namelen= 0;

         /*把用户空间的地址移动到内核空间中*/

         if(addr) {

                   err= move_addr_to_kernel(addr, addr_len,(struct sockaddr *)&address);

                   if(err < 0)

                            gotoout_put;

                   msg.msg_name= (struct sockaddr *)&address;

                   msg.msg_namelen= addr_len;

         }

         if(sock->file->f_flags & O_NONBLOCK)

                   flags|= MSG_DONTWAIT;

         msg.msg_flags= flags;

         err= sock_sendmsg(sock, &msg, len);

}

 

在sendto的系统调用(sys_sendto)里,会调用到sock_sendmsg()函数,该函数代码如下:

int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)

{

         structkiocb iocb;

         structsock_iocb siocb;

         intret;

         init_sync_kiocb(&iocb,NULL);

         iocb.private= &siocb;

         ret= __sock_sendmsg(&iocb, sock, msg, size);

         if(-EIOCBQUEUED == ret)

                   ret= wait_on_sync_kiocb(&iocb);

         returnret;

}

接下来调用__sock_sendmsg()函数。

static inline int __sock_sendmsg(struct kiocb *iocb,struct socket *sock, struct msghdr *msg, size_t size)

{

         interr = security_socket_sendmsg(sock, msg, size);

         returnerr ?: __sock_sendmsg_nosec(iocb, sock, msg, size);

}

再往下一步就是__sock_sendmsg_nosec函数。在__sock_sendmsg_nosec()函数中会返回一个sendmsg函数指针。

static inline int __sock_sendmsg_nosec(struct kiocb*iocb, struct socket *sock, struct msghdr *msg, size_t size)

{

         structsock_iocb *si = kiocb_to_siocb(iocb);

         sock_update_classid(sock->sk);

         si->sock= sock;

         si->scm= NULL;

         si->msg= msg;

         si->size= size;

         returnsock->ops->sendmsg(iocb, sock,msg, size);

}

在/net/can/raw.c源文件中,将raw_sendmsg函数地址赋给sendmsg函数指针,即在函数__sock_sendmsg_nosec()中return sock->ops->sendmsg(iocb,sock, msg, size),返回的函数指针将指向raw_sendmsg()函数。

static const struct proto_ops raw_ops = {

         .family        = PF_CAN,

         .release       = raw_release,

         .bind          = raw_bind,

         .connect       = sock_no_connect,

         .socketpair    = sock_no_socketpair,

         .accept        = sock_no_accept,

         .getname       = raw_getname,

         .poll          = datagram_poll,

         .ioctl         = can_ioctl,    /* use can_ioctl() from af_can.c */

         .listen        = sock_no_listen,

         .shutdown      = sock_no_shutdown,

         .setsockopt    = raw_setsockopt,

         .getsockopt    = raw_getsockopt,

         .sendmsg       = raw_sendmsg,

         .recvmsg       = raw_recvmsg,

         .mmap          = sock_no_mmap,

         .sendpage      = sock_no_sendpage,

};

 

static int raw_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_tsize)

{

         structsock *sk = sock->sk;

         structraw_sock *ro = raw_sk(sk);

         structsk_buff *skb;

         structnet_device *dev;

         intifindex;

         interr;

         if(msg->msg_name) {

                   structsockaddr_can *addr =

                            (structsockaddr_can *)msg->msg_name;

                   if(msg->msg_namelen < sizeof(*addr))

                            return-EINVAL;

                   if(addr->can_family != AF_CAN)

                            return-EINVAL;

                   ifindex= addr->can_ifindex;

         }else

                   ifindex= ro->ifindex;

         if(size != sizeof(struct can_frame))

                   return-EINVAL;

         dev= dev_get_by_index(&init_net, ifindex);

         if(!dev)

                   return-ENXIO;

         skb= sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT,

                                       &err);

         if(!skb)

                   gotoput_dev;

         err= memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);

         if(err < 0)

                   gotofree_skb;

         err= sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);

         if(err < 0)

                   gotofree_skb;

         /*to be able to check the received tx sock reference in raw_rcv() */

         skb_shinfo(skb)->tx_flags|= SKBTX_DRV_NEEDS_SK_REF;

         skb->dev= dev;

         skb->sk  = sk;

         err= can_send(skb,ro->loopback);

         dev_put(dev);

         if(err)

                   gotosend_failed;

         returnsize;

}

         在net/can/af_can.c源文件中,can_send函数负责CAN协议层的数据传输,即传输一帧CAN报文(可选本地回环)。参数skb指针指向套接字缓冲区和在数据段的CAN帧。loop参数是在本地CAN套接字上为监听者提供回环。

int can_send(struct sk_buff *skb, int loop)

{

         structsk_buff *newskb = NULL;

         structcan_frame *cf = (struct can_frame *)skb->data;

         interr;

         if(skb->len != sizeof(struct can_frame) || cf->can_dlc > 8) {

                   kfree_skb(skb);

                   return-EINVAL;

         }

         if(skb->dev->type != ARPHRD_CAN) {

                   kfree_skb(skb);

                   return-EPERM;

         }

         if(!(skb->dev->flags & IFF_UP)) {

                   kfree_skb(skb);

                   return-ENETDOWN;

         }

         skb->protocol= htons(ETH_P_CAN);

         skb_reset_network_header(skb);

         skb_reset_transport_header(skb);

         if(loop) {

                   /*local loopback of sent CAN frames */

                   /*indication for the CAN driver: do loopback */

                   skb->pkt_type= PACKET_LOOPBACK;

                   if(!(skb->dev->flags & IFF_ECHO)) {

                            /*

                             * If the interface is not capable to doloopback

                             * itself, we do it here.

                             */

                            newskb= skb_clone(skb, GFP_ATOMIC);

                            if(!newskb) {

                                     kfree_skb(skb);

                                     return-ENOMEM;

                            }

                            newskb->sk= skb->sk;

                            newskb->ip_summed= CHECKSUM_UNNECESSARY;

                            newskb->pkt_type= PACKET_BROADCAST;

                   }

         }else {

                   /*indication for the CAN driver: no loopback required */

                   skb->pkt_type= PACKET_HOST;

         }

         /*send to netdevice */

         err= dev_queue_xmit(skb);

         if(err > 0)

                   err= net_xmit_errno(err);

         if(err) {

                   kfree_skb(newskb);

                   returnerr;

         }

         if(newskb)

                   netif_rx_ni(newskb);

         /*update statistics */

         can_stats.tx_frames++;

         can_stats.tx_frames_delta++;

         return0;

}

int dev_queue_xmit(struct sk_buff *skb)

{

         structnet_device *dev = skb->dev;

         structnetdev_queue *txq;

         structQdisc *q;

         intrc = -ENOMEM;

 

         /*Disable soft irqs for various locks below. Also

          * stops preemption for RCU.

          */

         rcu_read_lock_bh();

 

         txq= dev_pick_tx(dev, skb);

         q= rcu_dereference_bh(txq->qdisc);

 

#ifdef CONFIG_NET_CLS_ACT

         skb->tc_verd= SET_TC_AT(skb->tc_verd, AT_EGRESS);

#endif

         trace_net_dev_queue(skb);

         if(q->enqueue) {

                   rc= __dev_xmit_skb(skb, q, dev, txq);

                   gotoout;

         }

         if(dev->flags & IFF_UP) {

                   intcpu = smp_processor_id(); /* ok because BHs are off */

 

                   if(txq->xmit_lock_owner != cpu) {

 

                            if(__this_cpu_read(xmit_recursion) > RECURSION_LIMIT)

                                     gotorecursion_alert;

 

                            HARD_TX_LOCK(dev,txq, cpu);

 

                            if(!netif_tx_queue_stopped(txq)) {

                                     __this_cpu_inc(xmit_recursion);

                                     rc= dev_hard_start_xmit(skb, dev, txq);

                                     __this_cpu_dec(xmit_recursion);

                                     if(dev_xmit_complete(rc)) {

                                               HARD_TX_UNLOCK(dev,txq);

                                               gotoout;

                                     }

                            }

                            HARD_TX_UNLOCK(dev,txq);

                            if(net_ratelimit())

                                     printk(KERN_CRIT"Virtual device %s asks to "

                                            "queue packet!\n", dev->name);

                   }else {

                            /*Recursion is detected! It is possible,

                             * unfortunately

                             */

recursion_alert:

                            if(net_ratelimit())

                                     printk(KERN_CRIT"Dead loop on virtual device "

                                            "%s, fix it urgently!\n",dev->name);

                   }

         }

 

         rc= -ENETDOWN;

         rcu_read_unlock_bh();

 

         kfree_skb(skb);

         returnrc;

out:

         rcu_read_unlock_bh();

         returnrc;

}

int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, structnetdev_queue *txq)

{

         conststruct net_device_ops *ops = dev->netdev_ops;

         intrc = NETDEV_TX_OK;

         unsignedint skb_len;

         if(likely(!skb->next)) {

                   u32features;

                   /*

                    * If device doesn't need skb->dst, releaseit right now while

                    * its hot in this cpu cache

                    */

                   if(dev->priv_flags & IFF_XMIT_DST_RELEASE)

                            skb_dst_drop(skb);

                   if(!list_empty(&ptype_all))

                            dev_queue_xmit_nit(skb,dev);

                   skb_orphan_try(skb);

                   features= netif_skb_features(skb);

 

                   if(vlan_tx_tag_present(skb) &&

                       !(features & NETIF_F_HW_VLAN_TX)) {

                            skb = __vlan_put_tag(skb,vlan_tx_tag_get(skb));

                            if(unlikely(!skb))

                                     gotoout;

                            skb->vlan_tci= 0;

                   }

                   if(netif_needs_gso(skb, features)) {

                            if(unlikely(dev_gso_segment(skb, features)))

                                     gotoout_kfree_skb;

                            if(skb->next)

                                     gotogso;

                   }else {

                            if(skb_needs_linearize(skb, features) &&

                                __skb_linearize(skb))

                                     gotoout_kfree_skb;

                            /*If packet is not checksummed and device does not

                             * support checksumming for this protocol,complete

                             * checksumming here.

                             */

                            if(skb->ip_summed == CHECKSUM_PARTIAL) {

                                     skb_set_transport_header(skb,

                                               skb_checksum_start_offset(skb));

                                     if(!(features & NETIF_F_ALL_CSUM) &&

                                          skb_checksum_help(skb))

                                               gotoout_kfree_skb;

                            }

                   }

                   skb_len= skb->len;

                   rc= ops->ndo_start_xmit(skb, dev);

                   trace_net_dev_xmit(skb,rc, dev, skb_len);

                   if(rc == NETDEV_TX_OK)

                            txq_trans_update(txq);

                   returnrc;

         }

}

         以下开始进行到CAN的底层驱动代码了,由于CAN驱动是编译进内核中,所以在系统启动时会注册CAN驱动,注册CAN驱动过程中会初始化d_can_netdev_ops结构体变量。在这个过程中,d_can_netdev_ops结构体变量定义了3个函数指针,其中(*ndo_start_xmit)函数指针指向d_can_start_xmit函数的入口地址。

static const struct net_device_ops d_can_netdev_ops = {

         .ndo_open= d_can_open,

         .ndo_stop= d_can_close,

         .ndo_start_xmit =d_can_start_xmit,

};

 

static netdev_tx_t d_can_start_xmit(struct sk_buff*skb, structnet_device *dev)

{

         u32msg_obj_no;

         structd_can_priv *priv = netdev_priv(dev);

         structcan_frame *frame = (struct can_frame *)skb->data;

         if(can_dropped_invalid_skb(dev, skb))

                   returnNETDEV_TX_OK;

         msg_obj_no= get_tx_next_msg_obj(priv);

         /*prepare message object for transmission */

         d_can_write_msg_object(dev,D_CAN_IF_TX_NUM, frame, msg_obj_no);

         can_put_echo_skb(skb,dev, msg_obj_no - D_CAN_MSG_OBJ_TX_FIRST);

         /*

          * we have to stop the queue in case of a wraparound or

          * if the next TX message object is still inuse

          */

         priv->tx_next++;

         if(d_can_is_next_tx_obj_busy(priv, get_tx_next_msg_obj(priv)) ||

                   ((priv->tx_next& D_CAN_NEXT_MSG_OBJ_MASK) == 0))

                   netif_stop_queue(dev);

         returnNETDEV_TX_OK;

}

         在d_can_start_xmit()函数中,会调用d_can_write_msg_object()函数准备消息报文进行传输。

static void d_can_write_msg_object(struct net_device *dev, intiface, struct can_frame *frame, int objno)

{

         inti;

         unsignedint id;

         u32dataA = 0;

         u32dataB = 0;

         u32flags = 0;

         structd_can_priv *priv = netdev_priv(dev);

 

         if(!(frame->can_id & CAN_RTR_FLAG))

                   flags|= D_CAN_IF_ARB_DIR_XMIT;

 

         if(frame->can_id & CAN_EFF_FLAG) {

                   id= frame->can_id & CAN_EFF_MASK;

                   flags|= D_CAN_IF_ARB_MSGXTD;

         }else

                   id= ((frame->can_id & CAN_SFF_MASK) << 18);

 

         flags|= D_CAN_IF_ARB_MSGVAL;

         d_can_write(priv,D_CAN_IFARB(iface), IFX_WRITE_IDR(id) | flags);

 

         for(i = 0; i < frame->can_dlc; i++) {

                   if(frame->can_dlc <= 4)

                            dataA|= (frame->data[i] << (8 * i));

                   else{

                            if(i < 4)

                                     dataA|= (frame->data[i] << (8 * i));

                            else

                                     dataB|= (frame->data[i] << (8 * (i - 4)));

                   }

         }

 

         /*DATA write to Message object registers DATAA and DATAB */

         if(frame->can_dlc <= 4)

                   d_can_write(priv,D_CAN_IFDATA(iface), dataA);

         else{

                   d_can_write(priv,D_CAN_IFDATB(iface), dataB);

                   d_can_write(priv,D_CAN_IFDATA(iface), dataA);

         }

 

         /*enable TX interrupt for this message object */

         d_can_write(priv,D_CAN_IFMCTL(iface),

                            D_CAN_IF_MCTL_TXIE| D_CAN_IF_MCTL_EOB |

                            D_CAN_IF_MCTL_TXRQST| D_CAN_IF_MCTL_NEWDAT |

                            frame->can_dlc);

 

         /*Put message data into message RAM */

         d_can_object_put(dev,iface, objno, D_CAN_IF_CMD_ALL);

}

    以上即是作者对Socket CAN进行数据发送的理解。接下来,我们将分析Socket CAN的数据接收!

转载请注明出处:http://blog.csdn.net/Righthek 谢谢!

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

对Socket CAN的理解(3)——【Socket CAN发送数据流程】 的相关文章

  • C++类库

    如果你有一定的C基础可能学起来比较容易些 但是学习C 43 43 的过程中又要尽量避免去使用一些C中的思想 平时还要多看一些高手写的代码 遇到问题多多思考 怎样才能把问题抽象化 以使自己头脑中有类的概念 最后别忘了经常上机自己调调程序 这是
  • Mac上安装node和npm

    通过安装包来安装 第 1 步 xff1a 下载适用于 macOS 的 NPM 包 去Node JS官网下载Mac操作系统的npm包 您可以单击此处打开下载页面并为您的系统选择合适的文件 第 2 步 xff1a 按照指南运行包管理器 打开下载
  • Java Maven项目问题整理

    文章目录 src main java文件夹src test java文件夹src main java和src test java文件夹区别读取maven项目中src test resources里的配置文件maven 项目导入本地jar包
  • Lombok使用总结

    文章目录 介绍Lombok原理常用注解 64 Data 64 Getter 64 Setter 64 ToString 64 EqualsAndHashCode 64 NoArgsConstructor 64 AllArgsConstruc
  • 解决:PDFBox报的java.io.IOException: Missing root object specification in trailer

    文章目录 问题描述原因分析解决方案 问题描述 使用pdfbox类库操作pdf文件时 xff0c 遇到下面的报错信息 xff1a java io IOException Missing root object specification in
  • KEIL每次都要编译全部文件并且每个文件编译三次

    SYD8801是一款低功耗高性能蓝牙低功耗SOC xff0c 集成了高性能2 4GHz射频收发机 32位ARM Cortex M0处理器 128kB Flash存储器 以及丰富的数字接口 SYD8801片上集成了Balun无需阻抗匹配网络
  • Mac上Golang语言环境搭建

    文章目录 官网其他参考安装golang源码安装安装包安装使用homebrew安装 配置GOROOTGOPATHGOPROXYGOPRIVATEGONOSUMDB 安装测试 官网 目前无法在家里的直接访问golang org网站 xff1a
  • [已解决] Mac上docker安装prometheus报错:Are you trying to mount a directory onto a file (or vice-versa)?

    文章目录 项目场景问题描述原因分析解决方案 项目场景 Mac上通过docker安装prometheus 问题描述 docker run时 xff0c 会出现下面的报错 xff0c 导致容器启动失败 xff1a docker Error re
  • Mac上安装Node Exporter

    文章目录 安装Node Exporter方法一 xff1a 手动安装方法二 xff1a docker安装 运行测试 node exporter 可以采集机器 xff08 物理机 虚拟机 云主机等 xff09 的监控指标数据 xff0c 能够
  • Docker安装Grafana

    文章目录 Grafana介绍拉取镜像准备相关挂载目录及文件启动容器访问测试添加 Prometheus 数据源常见问题 看板配置 Grafana介绍 上篇博客介绍了prometheus的安装 xff1a Docker部署Prometheus
  • Springboot应用接入Prometheus监控

    文章目录 接入介绍操作步骤修改应用的依赖及配置步骤1 xff1a 修改 pom 依赖步骤2 xff1a 修改配置 本地验证prometheus配置 接入介绍 在使用 Spring Boot 作为开发框架时 xff0c 需要监控应用的状态 x
  • Spring Boot自带监控组件—Actuator介绍

    文章目录 Actuator介绍启用与暴露的区别Spring Boot集成Actuator应用监控框架Actuator监控端点启用端点端点的默认暴露规则案例 自定义端点 Actuator介绍 Actuator是Spring Boot提供的应用
  • Git Commit提交规范总结

    文章目录 前言git commit 提交规范提交消息头 commit message header 提交消息具体内容 commit message body 提交消息尾述 commit message footer Revert 表情 Em
  • 常用kubectl命令总结

    文章目录 配置kubeconfig帮助信息命令查看具体某一个命令的帮助信息列出全局的选项参数 xff08 适用所有的命令 xff09 显示合并的 kubeconfig 配置或一个指定的 kubeconfig 文件 基本命令罗列所支持的完整资
  • 解决:org.apache.catalina.connector.ClientAbortException: java.io.IOException: 断开的管道

    文章目录 项目场景问题描述原因分析解决方案 项目场景 jdk11 Spring Boot 2 x 项目 xff0c Tomcat容器 Nginx 问题描述 系统日志中 xff0c 时不时会出现下面的异常信息 xff1a org apache
  • 解决:No converter for [xxxx] with preset Content-Type ‘text/plain;version=0.0.4;charset=utf-8‘

    文章目录 项目背景问题描述问题分析解决方案方案一 xff1a 修改Controller定义方案二 xff1a 修改Controller返回值方案三 xff1a 全局处理 项目背景 Spring Boot 2 X 问题描述 错误信息如下 xf
  • SYD8821 串口模块使用说明【串口0中断要屏蔽底层调用】

    SYD8821是具有全球领先低功耗 RX 2 4mA 64 94 5dBm灵敏度 xff0c TX 4 3mA 64 0dBm输出功率 的蓝牙低功耗SOC芯片 xff0c 在极低电流下实现了优异的射频性能 xff0c 搭配176kB SRA
  • MySQL的information_schema库下的常用sql

    文章目录 information schema TABLES查看该数据库实例下所有库大小 MB为单位 查看该实例下各个库大小 MB为单位 查看表大小 MB为单位 熟练使用 information schema库里的表 显示在库里的表 xff
  • shell脚本批量转文件格式:dos2unix

    文章目录 可以使用shell脚本实现 xff1a span class token shebang important bin sh span span class token assign left variable dir span s
  • 解决:com.atomikos.icatch.SysException: Error in init: Log already in use? tmlog in ./

    文章目录 项目场景问题描述原因分析详细分析 解决方案 项目场景 Spring Boot 2 x xff0c 集成 atomikos 问题描述 今天在同一个环境启动两个项目时报错 xff0c 因为两个项目同时涉及到分布式事物和切换数据源相关

随机推荐

  • Nginx日志介绍

    文章目录 access log日志流量统计 access log 日志文件一般存放在 var log nginx 下 xff0c 可以使用 tail f命令查看access日志 span class token function tail
  • JVM (Micrometer)-4701面板参数介绍

    文章目录 Quick Facts 概览 堆和非堆内存有以下几个概念 I O Overview xff08 服务黄金指标 xff09 JVM Memory xff08 JVM内存 xff09 JVM Misc xff08 JVM负载 xff0
  • curl文件传输命令

    CURL curl transfer a URL curl 是一个利用URL语法在命令行下工作的文件传输工具 支持文件上传和下载 格式 curl options URLs URL xff1a 通过大括号指定多个url 示例 xff1a cu
  • RS-485信号解析

    这次来看看RS 485信号 使用绿联的USB转RS485模块 线用的颜色不对 xff0c 类型也不对 xff0c 实际使用中请用带屏蔽层的双绞线 示波器CH1是R xff08 B xff09 示波器CH2是R 43 xff08 A xff0
  • T t与T t = T()的区别

    主要的区别就是默认构造函数对内置类型的初始化上 如果没有T中没有定义构造函数 xff0c 则对于 T t xff0c 并不会对 t 中内置类型设置初始值 xff0c 是一个随机值 但对于 T t 61 T xff0c 对 t 中内置类型会设
  • Effective STL:杂记(一)

    1 避免使用vector lt bool gt vector lt bool gt 实际上并不能算是一个STL容器 xff0c 实际上也并不存储bool 因为一个对象要成为STL容器 xff0c 就必须满足C 43 43 标准的第23 1节
  • 限制长度双向链表的插入操作

    面试遇到的问题 xff0c 一开始面试官是问我有什么方案可以实现排行榜 xff0c 当时给出了两个方案 后面面试官又在我的其中一种方案上让我手写代码实现排序双线链表的插入 xff0c 根据score值插入 xff0c 并且链表长度限制在10
  • SYD8821 IIC模块使用说明

    SYD8821是具有全球领先低功耗 RX 2 4mA 64 94 5dBm灵敏度 xff0c TX 4 3mA 64 0dBm输出功率 的蓝牙低功耗SOC芯片 xff0c 在极低电流下实现了优异的射频性能 xff0c 搭配176kB SRA
  • Python下载文件时出现乱码的解决方法之一:Content-Encoding: gzip

    之前写过一个简单的爬虫程序 xff0c 这次想试着再写一个下载固定文件的爬虫程序 写完之后发现下载的文件 xff0c 有些是可以正常打开的 xff0c 而有些是提示了编码错误 xff0c 用wireshark抓包 xff0c 过滤出http
  • Python爬虫判断url链接的是下载文件还是html文件

    最近在写一个网络爬虫的代码 xff0c 提供命令行来下载文件或者是打印根域名下指定节点及深度的子节点 用的是urllib2库 xff0c 算是比较简单 xff0c 但是功能并没有很强大 说重点吧 xff0c 在实际爬网页的过程中 xff0c
  • recvmsg和sendmsg函数

    在unp第14章讲了这两个函数 xff0c 但是只是讲了两个数据结构及参数而已 xff0c 所以自己想根据介绍来重构udp回射的客户端程序 但是sendmsg和recvmsg都遇到了问题 xff0c 并且纠结了很久 xff0c 所以在此记录
  • STL中map的[]运算导致程序挂掉的问题

    在项目的开发中 xff0c 使用 设置map变量时 xff0c 出现了Segment Fault的问题 xff0c 使用GDB bt命令得到调用栈 xff08 中间部分被我去掉了 xff09 如下 xff1a 0 0x00000000008
  • 结构体的vector resize()与初始化

    转自 xff1a https www cnblogs com kongse qi p 6798873 html 序 xff1a 我们在使用vector的时候可以自定义里面的数据类型 例如这样 xff1a struct Edge int fr
  • new(p) T1(value) 的操作

    最近开始看 STL源码剖析 xff0c 看到空间配置器的时候 xff0c 发现这么一段代码 xff1a template lt class T1 class T2 gt inline void construct T1 p const T2
  • Protobuf 编码及序列化的记录

    工作中用到了protobuf xff0c 然后之前在面试的时候面试官就问了一个问题 xff0c 如果将int32类型的字段的值设置为0 xff0c 那还会将该值进行序列化吗 xff1f 当时是懵了的 xff0c 因为自己还没有研究这部分 当
  • STM32驱动lcd1602,并口8位 6800时序

    STM32驱动lcd1602 xff0c 并口8位 6800时序 一 LCD1602 xff08 3 3V硬件版本 xff09 简介 1 1 引脚 引脚 xff0c lcd1602采用标准接口 xff0c 6800时序8位并行数据传输 第
  • CAN总线详解

    1 简介 CAN是控制器局域网络 Controller Area Network CAN 的简称 xff0c 是一种能够实现分布式实时控制的串行通信网络 优点 xff1a 传输速度最高到1Mbps xff0c 通信距离最远到10km xff
  • VS C#工程三【使用配置文件保存应用程序里的配置数据】[Resources找不到][打印log到VS窗口]【安全从工程删除图片】[发布exe并附带动态链接库dll]

    SYD8801是一款低功耗高性能蓝牙低功耗SOC xff0c 集成了高性能2 4GHz射频收发机 32位ARM Cortex M0处理器 128kB Flash存储器 以及丰富的数字接口 SYD8801片上集成了Balun无需阻抗匹配网络
  • 对Socket CAN的理解(2)——【Socket的原理及使用】

    转载请注明出处 xff1a http blog csdn net Righthek 谢谢 xff01 为了能够对Socket CAN的深入理解 xff0c 我们需要了解Socket的机制 Socket的中文翻译为 插座 xff0c 在计算机
  • 对Socket CAN的理解(3)——【Socket CAN发送数据流程】

    转载请注明出处 xff1a http blog csdn net Righthek 谢谢 xff01 对于本文 xff0c 我们将从用户层使用Socket CAN进行数据发送时 xff0c 数据从用户空间到底层驱动的整个通信流程 xff0c