`
mmdev
  • 浏览: 12915482 次
  • 性别: Icon_minigender_1
  • 来自: 大连
文章分类
社区版块
存档分类
最新评论

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

 
阅读更多

例一:发送Signaling Packet:

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

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

<wbr></wbr>

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

<wbr></wbr>

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

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

<wbr>if(argc &lt; 2)<br><wbr>{<br><wbr><wbr>printf("\n%s &lt;bdaddr&gt;\n", argv[0]);<br><wbr><wbr>exit(0);<br><wbr>}</wbr></wbr></wbr></wbr></wbr></wbr></wbr>


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


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

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


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

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


<wbr>//get local bdaddr<br><wbr>len = sizeof(struct sockaddr_l2);<br><wbr>memset(&amp;local_l2_addr, 0, sizeof(struct sockaddr_l2));</wbr></wbr></wbr>

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

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

<wbr>for (i = 0; i &lt; size; i++)<br><wbr><wbr>send_buf[L2CAP_CMD_HDR_SIZE + i] = 'A';</wbr></wbr></wbr>

<wbr>l2cap_cmd_hdr *send_cmd = (l2cap_cmd_hdr *) send_buf;<br><wbr>l2cap_cmd_hdr *recv_cmd = (l2cap_cmd_hdr *) recv_buf;</wbr></wbr>

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

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

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

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


<wbr>close(l2_sck);<br><wbr><br><wbr><br><wbr></wbr></wbr></wbr></wbr>

<wbr>return 0;<br> }<br></wbr>

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

<wbr></wbr>

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


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

<wbr></wbr>

<wbr></wbr>

<wbr></wbr>

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

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

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

Server:

<wbr></wbr>

#include <stdio.h>
#include <sys/types.h><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><br> #include &lt;sys/socket.h&gt;<br> #include &lt;stdlib.h&gt;<br> #include &lt;poll.h&gt;</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>


#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)
{
<wbr>int iRel = 0;<br><wbr>int sk = 0;<br><wbr>struct sockaddr_l2 local_addr;<br><wbr>struct sockaddr_l2 remote_addr;<br><wbr>int len;<br><wbr>int nsk = 0;<br><wbr>pthread_t nth = 0;<br><wbr>struct l2cap_options opts;<br><wbr>int optlen = 0;<br><wbr>int slen = 0;<br><wbr>char str[16] = {0};</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

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

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


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


<wbr>//get opts</wbr>

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


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


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

<wbr></wbr>

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

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

<wbr>return 0;<br> }</wbr>


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

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

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

<wbr></wbr>

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

<wbr><wbr><wbr>break;<br><wbr><wbr>}</wbr></wbr></wbr></wbr></wbr>

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

<wbr>return 0;<br> }<br></wbr>

<wbr></wbr>

<wbr></wbr>

client:

#include <stdio.h>
#include <sys/types.h><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><br> #include &lt;sys/socket.h&gt;<br> #include &lt;unistd.h&gt;</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>


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


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

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


<wbr>sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);<br><wbr>if(sk &lt; 0)<br><wbr>{<br><wbr><wbr>perror("\nsocket():");<br><wbr><wbr>exit(0);<br><wbr>}</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

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


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

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

<wbr>close(sk);<br><wbr>return 0;<br> }</wbr></wbr>

<wbr></wbr>

<wbr></wbr>

注意:

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

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

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

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics