linux 蓝牙与网络编程,L2CAP层编程实例 - Linux下Bluetooth编程_Linux编程_Linux公社-Linux系统门户网站...

例一:发送Signaling Packet:

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

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

765913fe29bfe7c734fb9a7e1171254c.gif

如果要直接发送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 \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

#include  #include

#include

#include

#include

#include

#include

#include

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

#include  #include

#include

#include

#include

#include

#include

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 \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。0b1331709591d260c1c78e86d0c51c18.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值