• (转)linux下bluetooth编程(六)L2CAP层编程实例


    例一:发送Signaling Packet:

    Signaling Command是2个Bluetooth实体之间的L2CAP层命令传输。所以得Signaling Command使用CID 0x0001.

    多个Command可以在一个C-frame(control frame)中发送。

     

     如果要直接发送Signaling Command.需要建立SOCK_RAW类型的L2CAP连接Socket。这样才有机会自己填充Command Code,Identifier等。

    以下是一个发送signaling Command以及接收Response的简单例子:

    int main(int argc, char** argv)
    {
     int l2_sck = 0;
     int iRel  = 0;
     struct sockaddr_l2 local_l2_addr;
     struct sockaddr_l2 remote_l2_addr;
     char str[24] ={0};
     int len = 0;
     int size = 50;
     char* send_buf;
     char* recv_buf;
     int i = 0;
     int id = 1; //不要为0
     
     send_buf = malloc(L2CAP_CMD_HDR_SIZE + size);
     recv_buf = malloc(L2CAP_CMD_HDR_SIZE + size);
     

     if(argc < 2)
     {
      printf("\n%s <bdaddr>\n", argv[0]);
      exit(0);
     }


     // create l2cap raw socket
     l2_sck = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP); //创建L2CAP protocol的RAW Packet
     if(l2_sck < 0)
     {
      perror("\nsocket:");
      return -1;
     }


     //bind
     memset(&local_l2_addr, 0, sizeof(struct sockaddr_l2));
     local_l2_addr.l2_family = PF_BLUETOOTH;
     bacpy(&local_l2_addr.l2_bdaddr , BDADDR_ANY);

     iRel = bind(l2_sck, (struct sockaddr*) &local_l2_addr, sizeof(struct sockaddr_l2));
     if(iRel < 0)
     {
      perror("\nbind()");
      exit(0);
     }


     //connect
     memset(&remote_l2_addr, 0 , sizeof(struct sockaddr_l2));
     remote_l2_addr.l2_family = PF_BLUETOOTH;
     //printf("\nConnect to %s\n", argv[1]);
     str2ba(argv[1], &remote_l2_addr.l2_bdaddr);

     iRel = connect(l2_sck, (struct sockaddr*)&remote_l2_addr, sizeof(struct sockaddr_l2));
     if(iRel < 0)
     {
      perror("\nconnect()");
      exit(0);
     }


     //get local bdaddr
     len = sizeof(struct sockaddr_l2);
     memset(&local_l2_addr, 0, sizeof(struct sockaddr_l2));

    //注意,getsockname()参数三是一个输入输出参数。输入时,为参数二的总体长度。输出时,

    //为实际长度。
     iRel = getsockname(l2_sck, (struct sockaddr*) &local_l2_addr, &len);
     if(iRel < 0)
     {
      perror("\ngetsockname()");
      exit(0);
     }
     ba2str(&(local_l2_addr.l2_bdaddr), str);
     //printf("\nLocal Socket bdaddr:[%s]\n", str);
     printf("l2ping: [%s] from [%s](data size %d) ...\n", argv[1], str, size);

     for (i = 0; i < size; i++)
      send_buf[L2CAP_CMD_HDR_SIZE + i] = 'A';

     l2cap_cmd_hdr *send_cmd = (l2cap_cmd_hdr *) send_buf;
     l2cap_cmd_hdr *recv_cmd = (l2cap_cmd_hdr *) recv_buf;

     send_cmd->ident = id;  //如上图所示,这一项为此Command Identifier
     send_cmd->len   = htobs(size);
     send_cmd->code = L2CAP_ECHO_REQ;  //如上图所示,此项为Command code.这项定为:

    //Echo Request。对端会发送Response回来。code=L2CAP_ECHO_RSP

     
     while(1)
     {
      send_cmd->ident = id;
      if(send(l2_sck, send_buf, size + L2CAP_CMD_HDR_SIZE, 0) <= 0)
      {
       perror("\nsend():");
      }
      
      while(1)
      {
       if(recv(l2_sck, recv_buf, size + L2CAP_CMD_HDR_SIZE, 0) <= 0)
       {
        perror("\nrecv()");
       }
       
       if (recv_cmd->ident != id)
        continue;

       if( recv_cmd->code == L2CAP_ECHO_RSP)
       {
        //printf("\nReceive Response Packet.\n");
        printf("%d bytes from [%s] id %d\n", recv_cmd->len, argv[1], recv_cmd->ident);
        break;
       }
       
      }
      sleep(1);
      id ++;
      
     }


     close(l2_sck);
     
     
     

     return 0;
    }

    所以说,如果想要发送接收signaling Command。只需要建立l2cap RAW socket. 并按规则填充command id, command code等。就可以接收发送了。

    Command Code: 这个值放在l2cap.h中。


    #define L2CAP_COMMAND_REJ 0x01
    #define L2CAP_CONN_REQ  0x02
    #define L2CAP_CONN_RSP  0x03
    #define L2CAP_CONF_REQ  0x04
    #define L2CAP_CONF_RSP  0x05
    #define L2CAP_DISCONN_REQ 0x06
    #define L2CAP_DISCONN_RSP 0x07
    #define L2CAP_ECHO_REQ  0x08
    #define L2CAP_ECHO_RSP  0x09
    #define L2CAP_INFO_REQ  0x0a
    #define L2CAP_INFO_RSP  0x0b

    例二:任意PSM的L2CAP连接间数据的传输:

    此例子中:Server,client其实是使用网络的概念定义的。

    server用来监听指定PSM的连接,并监听数据。同时,利用poll来查看peer是否断掉了。

    Server:

    #include <stdio.h>
    #include <sys/types.h>         
    #include <sys/socket.h>
    #include <stdlib.h>
    #include <poll.h>


    #include <bluetooth/bluetooth.h>
    #include <bluetooth/hci.h>
    #include <bluetooth/hci_lib.h>
    #include <bluetooth/l2cap.h>


    void * Read_thread(void* pSK);

    int main(int argc, char** argv)
    {
     int iRel = 0;
     int sk = 0;
     struct sockaddr_l2 local_addr;
     struct sockaddr_l2 remote_addr;
     int len;
     int nsk = 0;
     pthread_t nth = 0;
     struct l2cap_options opts;
     int optlen = 0;
     int slen = 0;
     char str[16] = {0};

     if(argc < 2)
     {
      printf("\nUsage:%s psm\n", argv[0]);
      exit(0);
     }

     
     // create l2cap socket
     sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);  //发送数据,使用SOCK_SEQPACKET为好
     if(sk < 0)
     {
      perror("\nsocket():");
      exit(0);
     }


     //bind
     local_addr.l2_family = PF_BLUETOOTH;
     local_addr.l2_psm = htobs(atoi(argv[argc -1]));  //last psm
     bacpy(&local_addr.l2_bdaddr, BDADDR_ANY);
     iRel = bind(sk, (struct sockaddr *)&local_addr, sizeof(struct sockaddr));
     if(iRel < 0)
     {
      perror("\nbind()");
      exit(0);
     }


     //get opts

    // in mtu 和 out mtu.每个包的最大值
     memset(&opts, 0, sizeof(opts));
     optlen = sizeof(opts);
     getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &optlen);
     printf("\nomtu:[%d]. imtu:[%d]. flush_to:[%d]. mode:[%d]\n", opts.omtu, opts.imtu, opts.flush_to, opts.mode);


     //set opts. default value
     opts.omtu = 0;
     opts.imtu = 672;
     if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0)
     {
      perror("\nsetsockopt():");
      exit(0);
     }


     //listen
     iRel = listen(sk, 10);
     if(iRel < 0)
     {
      perror("\nlisten()");
      exit(0);
     }

     len = sizeof(struct sockaddr_l2);
     while(1)
     {
      memset(&remote_addr, 0, sizeof(struct sockaddr_l2));
      nsk = accept(sk, (struct sockaddr*)(&remote_addr), &len);
      if(nsk < 0)
      {
       perror("\naccept():");
       continue;
      }
      ba2str(&(remote_addr.l2_bdaddr), str);
      printf("\npeer bdaddr:[%s].\n", str);  //得到peer的信息

      iRel = pthread_create(&nth, NULL, Read_thread, &nsk);
      if(iRel != 0)
      {
       perror("pthread_create():");
       continue;
      }
      pthread_detach(nth);  // 分离之
      
     }
     

     return 0;
    }


    void * Read_thread(void* pSK)
    {
     //struct pollfd fds[10];
     struct   pollfd   fds[100];
     char buf[1024] = {0};
     int iRel = 0;
     int exit_val = 0;
     

     //fds[0].fd = *(int*)pSK;
     //fds[0].events = POLLIN | POLLHUP;

     fds[0].fd   =   (int)(*(int*)pSK);
     fds[0].events   =   POLLIN   |   POLLHUP;

     while(1)
     {
      if(poll(fds, 1, -1) < 0)
      {
       perror("\npoll():");
      }
      if(fds[0].revents & POLLHUP)
      {
       //hang up
       printf("\n[%d] Hang up\n", *(int*)pSK);
       close(*(int*)pSK);
       pthread_exit(&exit_val);

       break;
      }

      if(fds[0].revents & POLLIN)
      {
       memset(buf, 0 , 1024);
       //read data
       iRel = recv(*(int*)pSK, buf, 572, 0);
       //printf("\nHandle[%d] Receive [%d] data:[%s]", *(int*)pSK, iRel, buf);
      }
      
     }

     return 0;
    }

    client:

    #include <stdio.h>
    #include <sys/types.h>         
    #include <sys/socket.h>
    #include <unistd.h>


    #include <bluetooth/bluetooth.h>
    #include <bluetooth/hci.h>
    #include <bluetooth/hci_lib.h>
    #include <bluetooth/l2cap.h>


    int main(int argc, char** argv)
    {
     int sk;
     int i = 0;
     char buf[24] = "Sam is Good Guy!";
     struct sockaddr_l2 local_addr;
     struct sockaddr_l2 remote_addr;
     int iRel = 0;

     if(argc < 3)
     {
      printf("\nUsage:%s <bdaddr> <PSM>\n", argv[0]);
      exit(0);
     }


     sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
     if(sk < 0)
     {
      perror("\nsocket():");
      exit(0);
     }

     //bind. bluetooth好像不许有无名Socket
     local_addr.l2_family = PF_BLUETOOTH;
     bacpy(&local_addr.l2_bdaddr, BDADDR_ANY);
     iRel = bind(sk, (struct sockaddr *)&local_addr, sizeof(struct sockaddr));
     if(iRel < 0)
     {
      perror("\nbind()");
      exit(0);
     }


     memset(&remote_addr, 0, sizeof(struct sockaddr_l2));
     remote_addr.l2_family = PF_BLUETOOTH;
     str2ba(argv[1], &remote_addr.l2_bdaddr);
     remote_addr.l2_psm = htobs(atoi(argv[argc -1]));
     
     connect(sk, (struct sockaddr*)&remote_addr, sizeof(struct sockaddr_l2));

     for(i = 0; i < 60; i++)
     {
      iRel = send(sk, buf, strlen(buf)+1, 0);
      printf("Send [%d] data\n", strlen(buf)+1);
      sleep(1);
     }

     close(sk);
     return 0;
    }

    注意:

    1. 在Linux 网络编程中,主动发起连接方,因为不关心地址具体是什么,所以可以作为无名socket,也就是说可以不bind. 但Bluetooth则不可以,一定需要bind.

    2. poll可以查出连接断连,但需要注意:断开的revent值为:11001B。也就是说:POLLIN | POLLERR |POLLHUP。

    3. 被连接一方,一定要指定PSM。

    continue my dream...
  • 相关阅读:
    58. 最后一个单词的长度
    53. 最大子序和
    50. Pow(x, n)
    35. 搜索插入位置
    28. 实现 strStr()
    leetcode 27. 移除元素
    leetcode 26. 删除排序数组中的重复项
    leetcode 21. 合并两个有序链表
    20. 有效的括号
    多线程案例_循环打印_设计4个线程...
  • 原文地址:https://www.cnblogs.com/chenbin7/p/2726519.html
Copyright © 2020-2023  润新知