简体   繁体   English

通过SocketCAN提升:: asio

[英]boost::asio over SocketCAN

I was thinking of making use of Boost Asio to read data from a Socket CAN . 我正在考虑利用Boost AsioSocket CAN读取数据。 There's nothing fancy going on in linux/can.h , and the device should behave like the loopback interface, and be used with a raw socket. linux / can.h中没有任何花哨的东西,设备应该像loopback接口一样,并与原始套接字一起使用。

Looking at the basic_raw_socket interface it seems that I can make use of basic_raw_socket::assign to assign the native socket created with 看看basic_raw_socket接口,似乎我可以利用basic_raw_socket :: assign来分配用它创建的本机套接字

socket( PF_CAN, SOCK_RAW, CAN_RAW );

This is what I have so far 这就是我到目前为止所拥有的

namespace can {
       class CanSocket {
       public:
               typedef boost::asio::ip::basic_endpoint<CanSocket> endpoint;
               typedef boost::asio::ip::basic_resolver_query<CanSocket> resolver_query;
               typedef boost::asio::ip::basic_resolver_iterator<CanSocket> resolver_iterator;
               typedef boost::asio::basic_raw_socket<CanSocket> socket;
               typedef boost::asio::ip::basic_resolver<CanSocket> resolver;

               CanSocket()
                       : _protocol( CAN_RAW )
                       , _family( PF_CAN )
               {
               }

               static CanSocket v4()
               {
                       return CanSocket();
               }
               static CanSocket v6();
               int type() const;
               int protocol() const;
               int family() const;

               friend bool operator==(const CanSocket& p1, const CanSocket& p2)
               {
                       return p1._protocol != p2._protocol || p1._family != p2._family;
               }
               friend bool operator!=(const CanSocket& p1, const CanSocket& p2)
               {
                       return p1._protocol == p2._protocol || p1._family == p2._family;
               }

       private:
               int _protocol;
               int _family;
};
}

And this is how I use it in my application 这就是我在我的应用程序中使用它的方式

   boost::asio::io_service ioserv;

   CanSocket::socket s( ioserv );

   int sock = socket( PF_CAN, SOCK_RAW, CAN_RAW );

   s.assign(CanSocket::v4(), sock);

   struct ifreq ifr;
   strcpy(ifr.ifr_name, "vcan0");
   ioctl(sock, SIOCGIFINDEX, &ifr); /* ifr.ifr_ifindex gets filled
                                 * with that device's index */

   /* Select that CAN interface, and bind the socket to it. */

   /* this should be the endpoint */
   struct sockaddr_can addr;
   addr.can_family = AF_CAN;
   addr.can_ifindex = ifr.ifr_ifindex;

   /* s.bind (....) */
   bind( sock, (struct sockaddr*)&addr, sizeof(addr) );

What I don't quite get is how do I bind s to the local endpoint? 我不太了解的是如何 s 绑定到本地端点? There are no IPs or ports involved. 没有涉及IP或端口。

Is there anything else that should be implemented besides the endpoint to get it going? 除了端点之外还有其他任何东西可以实现吗?

Here is working example, assembled with help of this thread 这是一个工作示例,在此线程的帮助下组装

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <iostream>

#include <net/if.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>

#include <linux/can.h>
#include <linux/can/raw.h>

#include <boost/asio.hpp>
#include <boost/bind.hpp>

void data_send(void) {
  std::cout << "omg sent" << std::endl;
}

void data_rec(struct can_frame &rec_frame,
              boost::asio::posix::basic_stream_descriptor<> &stream) {
  std::cout << std::hex << rec_frame.can_id << "  ";
  for (int i = 0; i < rec_frame.can_dlc; i++) {
    std::cout << std::hex << int(rec_frame.data[i]) << " ";
  }
  std::cout << std::dec << std::endl;
  stream.async_read_some(
      boost::asio::buffer(&rec_frame, sizeof(rec_frame)),
      boost::bind(data_rec, boost::ref(rec_frame), boost::ref(stream)));
}

int main(void) {
  struct sockaddr_can addr;
  struct can_frame frame;
  struct can_frame rec_frame;
  struct ifreq ifr;

  int natsock = socket(PF_CAN, SOCK_RAW, CAN_RAW);

  strcpy(ifr.ifr_name, "vcan0");
  ioctl(natsock, SIOCGIFINDEX, &ifr);

  addr.can_family = AF_CAN;
  addr.can_ifindex = ifr.ifr_ifindex;
  if (bind(natsock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
    perror("Error in socket bind");
    return -2;
  }

  frame.can_id = 0x123;
  frame.can_dlc = 2;
  frame.data[0] = 0x11;
  frame.data[1] = 0x23;

  boost::asio::io_service ios;
  boost::asio::posix::basic_stream_descriptor<> stream(ios);
  stream.assign(natsock);

  stream.async_write_some(boost::asio::buffer(&frame, sizeof(frame)),
                          boost::bind(data_send));
  stream.async_read_some(
      boost::asio::buffer(&rec_frame, sizeof(rec_frame)),
      boost::bind(data_rec, boost::ref(rec_frame), boost::ref(stream)));
  ios.run();
}

The solution is to use posix::stream_descriptor . 解决方案是使用posix::stream_descriptor

Just open the native socket, bind and then use posix::basic_stream_descriptor::assign . 只需打开本机套接字,绑定然后使用posix::basic_stream_descriptor::assign

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM