zoukankan      html  css  js  c++  java
  • (转)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...
  • 相关阅读:
    GitLab 介绍
    git 标签
    git 分支
    git 仓库 撤销提交 git reset and 查看本地历史操作 git reflog
    git 仓库 回退功能 git checkout
    python 并发编程 多进程 练习题
    git 命令 查看历史提交 git log
    git 命令 git diff 查看 Git 区域文件的具体改动
    POJ 2608
    POJ 2610
  • 原文地址:https://www.cnblogs.com/chenbin7/p/2726519.html
Copyright © 2011-2022 走看看