Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1297643
  • 博文数量: 860
  • 博客积分: 425
  • 博客等级: 下士
  • 技术积分: 1464
  • 用 户 组: 普通用户
  • 注册时间: 2011-08-20 19:57
个人简介

对技术执着

文章分类

全部博文(860)

文章存档

2019年(16)

2018年(12)

2015年(732)

2013年(85)

2012年(15)

我的朋友

分类: LINUX

2012-10-17 17:31:35

例一:发送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 \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。

例一:发送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 \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。

阅读(8470) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~