{"id":974,"date":"2021-12-19T16:11:55","date_gmt":"2021-12-19T08:11:55","guid":{"rendered":"https:\/\/blog.cauchyschwarz.com\/?p=974"},"modified":"2021-12-19T16:11:58","modified_gmt":"2021-12-19T08:11:58","slug":"%e8%93%9d%e7%89%99","status":"publish","type":"post","link":"https:\/\/blog.cauchyschwarz.com\/?p=974","title":{"rendered":"\u84dd\u7259"},"content":{"rendered":"\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_82_2 ez-toc-wrap-right counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<label for=\"ez-toc-cssicon-toggle-item-69e9f4a89657f\" class=\"ez-toc-cssicon-toggle-label\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/label><input type=\"checkbox\"  id=\"ez-toc-cssicon-toggle-item-69e9f4a89657f\" checked aria-label=\"Toggle\" \/><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/blog.cauchyschwarz.com\/?p=974\/#%E5%8F%82%E8%80%83%E6%9D%A5%E6%BA%90\" >\u53c2\u8003\u6765\u6e90<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/blog.cauchyschwarz.com\/?p=974\/#%E8%93%9D%E7%89%99\" >\u84dd\u7259<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/blog.cauchyschwarz.com\/?p=974\/#%E5%8E%9F%E6%95%99%E7%A8%8B\" >\u539f\u6559\u7a0b<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/blog.cauchyschwarz.com\/?p=974\/#%E8%93%9D%E7%89%99%E7%BC%96%E7%A8%8B%E5%8E%9F%E7%90%86\" >\u84dd\u7259\u7f16\u7a0b\u539f\u7406<\/a><ul class='ez-toc-list-level-2' ><li class='ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/blog.cauchyschwarz.com\/?p=974\/#%E5%AF%BB%E5%9D%80\" >\u5bfb\u5740<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/blog.cauchyschwarz.com\/?p=974\/#%E5%8D%8F%E8%AE%AE\" >\u534f\u8bae<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/blog.cauchyschwarz.com\/?p=974\/#bluez%E4%B8%8EC\" >bluez\u4e0eC<\/a><ul class='ez-toc-list-level-2' ><li class='ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/blog.cauchyschwarz.com\/?p=974\/#%E5%AE%89%E8%A3%85BlueZ\" >\u5b89\u88c5BlueZ<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/blog.cauchyschwarz.com\/?p=974\/#%E6%9F%A5%E8%AF%A2%E5%91%A8%E5%9B%B4%E8%AE%BE%E5%A4%87\" >\u67e5\u8be2\u5468\u56f4\u8bbe\u5907<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/blog.cauchyschwarz.com\/?p=974\/#RFCOMM%E8%BF%9E%E6%8E%A5\" >RFCOMM\u8fde\u63a5<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/blog.cauchyschwarz.com\/?p=974\/#L2CAP%E8%BF%9E%E6%8E%A5\" >L2CAP\u8fde\u63a5<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-12\" href=\"https:\/\/blog.cauchyschwarz.com\/?p=974\/#%E4%BD%BF%E7%94%A8SDP\" >\u4f7f\u7528SDP<\/a><\/li><\/ul><\/li><\/ul><\/nav><\/div>\n<h1 class=\"wp-block-heading\" id=\"%E5%8F%82%E8%80%83%E6%9D%A5%E6%BA%90\"><span class=\"ez-toc-section\" id=\"%E5%8F%82%E8%80%83%E6%9D%A5%E6%BA%90\"><\/span><a href=\"http:\/\/blog.sina.com.cn\/s\/blog_602f87700100e57t.html\">\u53c2\u8003\u6765\u6e90<\/a><span class=\"ez-toc-section-end\"><\/span><\/h1>\n\n\n\n<p>\u4ee5\u53ca\u901a\u8fc7Google\u3001\u767e\u5ea6\u67e5\u5230\u7684\u5176\u4ed6\u8d44\u6599<\/p>\n\n\n\n<h1 class=\"wp-block-heading\" id=\"%E8%93%9D%E7%89%99\"><span class=\"ez-toc-section\" id=\"%E8%93%9D%E7%89%99\"><\/span>\u84dd\u7259<span class=\"ez-toc-section-end\"><\/span><\/h1>\n\n\n\n<ul class=\"wp-block-list\"><li>\u63d0\u51fa\u8005 1998\u5e74\uff0c\u7231\u7acb\u4fe1\u3001\u8bfa\u57fa\u4e9a\u3001\u4e1c\u829d\u3001IBM\u3001Intel\u3002<\/li><li>\u540d\u5b57\u7531\u6765 \u84dd\u7259\u6280\u672f\u7edf\u4e00\u4e86\u6807\u51c6\u4e0d\u4e00\u7684\u77ed\u8ddd\u79bb\u65e0\u7ebf\u4f20\u8f93\u6280\u672f\uff0c\u5c31\u5982\u540cHarald Blatand\u7edf\u4e00\u4e86\u4e39\u9ea6\u548c\u632a\u5a01\uff0c\u56e0\u6b64\u7528\u4ed6\u7684\u5916\u53f7Bluetooth\u6765\u547d\u540d\u8fd9\u9879\u6280\u672f(Blatand\u7ffb\u8bd1\u4e3a\u82f1\u8bed\u65f6\u5c31\u662fBluetooth)\u3002<\/li><li>\u7279\u70b9 \u4f20\u8f93\u8ddd\u79bb10cm~10m\uff0c\u4f7f\u7528\u9891\u6bb52.4GHz<\/li><li>\u5df2\u7ecf\u5b9e\u73b0\u7684\u84dd\u7259\u534f\u8bae\u6808<ul><li><a href=\"https:\/\/file+.vscode-resource.vscode-webview.net\/home\/kid\/workshop\/blog\/blog\/_posts\/Arsenal\/bluetooth\/www.bluez.org\">BlueZ<\/a>\u00a0Linux\u5b98\u65b9\u7684\u84dd\u7259\u534f\u8bae\u6808\uff0c\u4e0a\u5c42\u7528socket\u5c01\u88c5\uff0c\u4f7f\u7528\u65f6\u7c7b\u4f3c\u4e8e\u666e\u901a\u7684\u7f51\u7edc\u7f16\u7a0b\u3002\u95ee\u9898\u662f\u6ca1\u770b\u89c1\u76f8\u5173\u7684\u597d\u7684\u6587\u6863\u3002<\/li><\/ul><\/li><\/ul>\n\n\n\n<h1 class=\"wp-block-heading\" id=\"%E5%8E%9F%E6%95%99%E7%A8%8B\"><span class=\"ez-toc-section\" id=\"%E5%8E%9F%E6%95%99%E7%A8%8B\"><\/span><a href=\"https:\/\/people.csail.mit.edu\/albert\/bluez-intro\/index.html\">\u539f\u6559\u7a0b<\/a><span class=\"ez-toc-section-end\"><\/span><\/h1>\n\n\n\n<p>\u8be5\u6559\u7a0b\u8bb2\u8ff0\u4e86\u5982\u4f55\u5229\u7528bluez\u8fdb\u884c\u7b80\u5355\u7684\u84dd\u7259\u7f16\u7a0b(C\u3001Python)\u3002\u7531\u4e8e\u6211\u53ea\u7528C\u7684\uff0c\u56e0\u6b64\u8fd9\u91cc\u5c31\u53ea\u6458\u53d6\u4e86\u5173\u4e8eC\u7684\u90e8\u5206\u53d9\u8ff0\u3002<\/p>\n\n\n\n<h1 class=\"wp-block-heading\" id=\"%E8%93%9D%E7%89%99%E7%BC%96%E7%A8%8B%E5%8E%9F%E7%90%86\"><span class=\"ez-toc-section\" id=\"%E8%93%9D%E7%89%99%E7%BC%96%E7%A8%8B%E5%8E%9F%E7%90%86\"><\/span>\u84dd\u7259\u7f16\u7a0b\u539f\u7406<span class=\"ez-toc-section-end\"><\/span><\/h1>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"%E5%AF%BB%E5%9D%80\"><span class=\"ez-toc-section\" id=\"%E5%AF%BB%E5%9D%80\"><\/span>\u5bfb\u5740<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li>\u8bbe\u5907\u5730\u5740(Bluetooth address\/device address) \u6bcf\u4e2a\u84dd\u7259\u82af\u7247\u90fd\u6709\u4e00\u4e2a\u72ec\u4e00\u65e0\u4e8c\u768448\u4f4d\u8bbe\u5907\u5730\u5740\uff1b\u5728\u84dd\u7259\u901a\u8baf\u7684\u6240\u6709\u5c42\u90fd\u4f1a\u4f7f\u7528\u8fd9\u4e2a\u8bbe\u5907\u5730\u5740\uff0c\u800c\u4e0d\u662f\u50cfTCP\/IP\u7f51\u7edc\u90a3\u6837\u53ea\u5728\u6570\u636e\u94fe\u8def\u5c42\u4f7f\u7528\u8bbe\u5907\u5730\u5740\u5728\u66f4\u9ad8\u5c42\u5c31\u53d8\u4e3a\u4f7f\u7528IP\u5730\u5740\u4e86\u3002<\/li><li>\u8bbe\u5907\u540d(Device Name) \u4e3a\u65b9\u4fbf\u4eba\u7c7b\u533a\u522b\u84dd\u7259\u8bbe\u5907\uff0c\u84dd\u7259\u8bbe\u5907\u5728\u8bbe\u5907\u5730\u5740\u4e4b\u5916\u63d0\u4f9b\u4e00\u4e2a\u8bbe\u5907\u540d\u65b9\u4fbf\u4eba\u7c7b\u5206\u8fa8\u3002\u4e0d\u540c\u7684\u84dd\u7259\u8bbe\u5907\u53ef\u4ee5\u6709\u76f8\u540c\u7684\u8bbe\u5907\u540d\uff0c\u4f46\u662f\u4e0d\u4f1a\u6709\u76f8\u540c\u7684\u8bbe\u5907\u5730\u5740\u3002<\/li><\/ul>\n\n\n\n<p>\u7c7b\u4f3c\u4e8e\u56e0\u7279\u7f51\u8fd8\u5b58\u5728\u7740TCP\/IP\u4e4b\u5916\u7684\u5176\u4ed6\u534f\u8bae(RFC)\uff0c\u84dd\u7259\u8bbe\u5907\u4e5f\u5b58\u5728\u7740\u7c7b\u4f3c\u7684\u79f0\u4e3aBluetooth Profile\u7684\u534f\u8bae\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"%E5%8D%8F%E8%AE%AE\"><span class=\"ez-toc-section\" id=\"%E5%8D%8F%E8%AE%AE\"><\/span>\u534f\u8bae<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>\u7c7b\u6bd4\u4e00\u822c\u7684\u7f51\u7edc\u7f16\u7a0b\uff0c\u84dd\u7259\u7684RFCOMM\u534f\u8bae\u7c7b\u4f3c\u4e8eTCP\u534f\u8bae\uff0cL2CAP\u534f\u8bae\u7c7b\u4f3c\u4e8eUDP\u534f\u8bae\u3002<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>protocol<\/th><th>terminology<\/th><th>reserved\/well-known ports<\/th><th>dynamically assigned ports<\/th><\/tr><\/thead><tbody><tr><td>TCP<\/td><td>port<\/td><td>1-1024<\/td><td>1025-65535<\/td><\/tr><tr><td>UDP<\/td><td>port<\/td><td>1-1024<\/td><td>1025-65535<\/td><\/tr><tr><td>RFCOMM<\/td><td>channel<\/td><td>none<\/td><td>1-30<\/td><\/tr><tr><td>L2CAP<\/td><td>PSM<\/td><td>odd numbered 1-4095<\/td><td>odd numbered 4097-32765<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<ul class=\"wp-block-list\"><li>\u5728L2CAP\u534f\u8bae\u4e2d\uff0c\u7aef\u53e3\u53f7\u88ab\u79f0\u4e3a<em>Protocol Service Multiplexers<\/em>\uff0c\u4e14\u53ea\u80fd\u4f7f\u75281-32767(\u4e0d\u542b32767)\u4e4b\u95f4\u7684\u5947\u6570\uff1b\u5728RFCOMM\u534f\u8bae\u4e2d\uff0c\u5219\u662f\u7528\u7684<em>channels<\/em>\uff0c\u53d6\u503c\u4e3a1-30(\u542b)\u3002<\/li><li>\u7531\u4e8eRFCOMM\u534f\u8bae\u53ea\u670930\u4e2a\u4e0d\u540c\u7684\u7aef\u53e3\u53f7\uff0c\u56e0\u6b64\u5f53\u540c\u4e00\u4e2a\u84dd\u7259\u8bbe\u5907\u4e0a\u67097\u4e2a\u670d\u52a1\u7aef\u5e94\u7528\u7a0b\u5e8f\u7684\u65f6\u5019\u5c31\u4f1a\u6709\u5927\u4e8e50%\u7684\u6982\u7387\u4ea7\u751f\u7aef\u53e3\u4f7f\u7528\u4e0a\u7684\u51b2\u7a81\u3002\u76f8\u6bd4\u4e8e\u7ed1\u5b9a\u56fa\u5b9a\u7684\u7aef\u53e3\u53f7\uff0c\u66f4\u597d\u7684\u89e3\u51b3\u529e\u6cd5\u662f\u4f7f\u7528<strong>Service Discovery Protocol(SDP)<\/strong>\u3002\u670d\u52a1\u7aef\u5e94\u7528\u7a0b\u5e8f\u5e76\u4e0d\u5728\u5f00\u53d1\u7a0b\u5e8f\u7684\u65f6\u5019\u5c31\u51b3\u5b9a\u7aef\u53e3\u53f7\uff0c\u800c\u662f\u5728\u8fd0\u884c\u65f6\u5411SDP\u6ce8\u518c\u670d\u52a1\uff0c\u7531SDP\u6307\u5b9a\u7aef\u53e3\u53f7\uff0c\u670d\u52a1\u7aef\u5e94\u7528\u7a0b\u5e8f\u5728\u6ce8\u518c\u65f6\u9700\u8981\u63d0\u4f9b\u4e00\u4e9b\u4fe1\u606f\uff0c\u8fd9\u4e9b\u4fe1\u606f\u5305\u62ec\u4e00\u4e2a128\u4f4d\u7684UUID\u3002\u5ba2\u6237\u7aef\u7a0b\u5e8f\u901a\u8fc7\u5411SDP\u670d\u52a1\u5668(SDP\u670d\u52a1\u7684\u7aef\u53e3\u53f7\u662f\u56fa\u5b9a\u548c\u77e5\u9053\u7684)\u67e5\u8be2\u5177\u6709\u6307\u5b9aUUID\u7684\u670d\u52a1\u6765\u627e\u5230\u76f8\u5e94\u7684\u670d\u52a1\u7aef\u5e94\u7528\u7a0b\u5e8f\u7684\u7aef\u53e3\u53f7\u3002<\/li><\/ul>\n\n\n\n<h1 class=\"wp-block-heading\" id=\"bluez%E4%B8%8Ec\"><span class=\"ez-toc-section\" id=\"bluez%E4%B8%8EC\"><\/span>bluez\u4e0eC<span class=\"ez-toc-section-end\"><\/span><\/h1>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"%E5%AE%89%E8%A3%85bluez\"><span class=\"ez-toc-section\" id=\"%E5%AE%89%E8%A3%85BlueZ\"><\/span>\u5b89\u88c5BlueZ<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>\u6211\u7684Ubuntu16.04\u8c8c\u4f3c\u9ed8\u8ba4\u5b89\u88c5\u4e86BlueZ\uff0c\u4f46\u662f\u8fd8\u9700\u8981\u5b89\u88c5\u4ee5\u4e0b\u4e1c\u897f\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">apt install libbluetooth-dev\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"%E6%9F%A5%E8%AF%A2%E5%91%A8%E5%9B%B4%E8%AE%BE%E5%A4%87\"><span class=\"ez-toc-section\" id=\"%E6%9F%A5%E8%AF%A2%E5%91%A8%E5%9B%B4%E8%AE%BE%E5%A4%87\"><\/span>\u67e5\u8be2\u5468\u56f4\u8bbe\u5907<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>\u6e90\u4ee3\u7801\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">#include &lt;stdio.h&gt;\n#include &lt;stdlib.h&gt;\n#include &lt;unistd.h&gt;\n#include &lt;sys\/socket.h&gt;\n#include &lt;bluetooth\/bluetooth.h&gt;\n#include &lt;bluetooth\/hci.h&gt;\n#include &lt;bluetooth\/hci_lib.h&gt;\n\nint main(int argc, char **argv)\n{\n    inquiry_info *ii = NULL;\n    int max_rsp, num_rsp;\n    int dev_id, sock, len, flags;\n    int i;\n    char addr[19] = { 0 };\n    char name[248] = { 0 };\n\n    dev_id = hci_get_route(NULL);\n    sock = hci_open_dev( dev_id );\n    if (dev_id &lt; 0 || sock &lt; 0) {\n        perror(\"opening socket\");\n        exit(1);\n    }\n\n    len  = 8;\n    max_rsp = 255;\n    flags = IREQ_CACHE_FLUSH;\n    ii = (inquiry_info*)malloc(max_rsp * sizeof(inquiry_info));\n    \n    num_rsp = hci_inquiry(dev_id, len, max_rsp, NULL, &amp;ii, flags);\n    if( num_rsp &lt; 0 ) perror(\"hci_inquiry\");\n\n    for (i = 0; i &lt; num_rsp; i++) {\n        ba2str(&amp;(ii+i)-&gt;bdaddr, addr);\n        memset(name, 0, sizeof(name));\n        if (hci_read_remote_name(sock, &amp;(ii+i)-&gt;bdaddr, sizeof(name), \n            name, 0) &lt; 0)\n        strcpy(name, \"[unknown]\");\n        printf(\"%s  %s\\n\", addr, name);\n    }\n\n    free( ii );\n    close( sock );\n    return 0;\n}\n<\/code><\/pre>\n\n\n\n<p>\u7f16\u8bd1\uff1a<\/p>\n\n\n\n<p><kbd>gcc -o simplescan simplescan.c -lbluetooth <\/kbd><\/p>\n\n\n\n<p>\u503c\u5f97\u6ce8\u610f\u7684\u65f6\uff0c<em>len<\/em>\u4ee3\u8868\u626b\u63cf\u65f6\u95f4\u4e3a<em>len*1.28<\/em>\u79d2\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"rfcomm%E8%BF%9E%E6%8E%A5\"><span class=\"ez-toc-section\" id=\"RFCOMM%E8%BF%9E%E6%8E%A5\"><\/span>RFCOMM\u8fde\u63a5<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>\u670d\u52a1\u5668\u7a0b\u5e8f\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">#include &lt;stdio.h&gt;\n#include &lt;unistd.h&gt;\n#include &lt;sys\/socket.h&gt;\n#include &lt;bluetooth\/bluetooth.h&gt;\n#include &lt;bluetooth\/rfcomm.h&gt;\n\nint main(int argc, char **argv)\n{\n    struct sockaddr_rc loc_addr = { 0 }, rem_addr = { 0 };\n    char buf[1024] = { 0 };\n    int s, client, bytes_read;\n    socklen_t opt = sizeof(rem_addr);\n\n    <em>\/\/ allocate socket<\/em>\n    s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);\n\n    <em>\/\/ bind socket to port 1 of the first available <\/em>\n    <em>\/\/ local bluetooth adapter<\/em>\n    loc_addr.rc_family = AF_BLUETOOTH;\n    loc_addr.rc_bdaddr = *BDADDR_ANY;\n    loc_addr.rc_channel = (uint8_t) 1;\n    bind(s, (struct sockaddr *)&amp;loc_addr, sizeof(loc_addr));\n\n    <em>\/\/ put socket into listening mode<\/em>\n    listen(s, 1);\n\n    <em>\/\/ accept one connection<\/em>\n    client = accept(s, (struct sockaddr *)&amp;rem_addr, &amp;opt);\n\n    ba2str( &amp;rem_addr.rc_bdaddr, buf );\n    fprintf(stderr, \"accepted connection from %s\\n\", buf);\n    memset(buf, 0, sizeof(buf));\n\n    <em>\/\/ read data from the client<\/em>\n    bytes_read = read(client, buf, sizeof(buf));\n    if( bytes_read &gt; 0 ) {\n        printf(\"received [%s]\\n\", buf);\n    }\n\n    <em>\/\/ close connection<\/em>\n    close(client);\n    close(s);\n    return 0;\n}\n<\/code><\/pre>\n\n\n\n<p>\u5ba2\u6237\u7aef\u7a0b\u5e8f\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">nclude &lt;stdio.h&gt;\n#include &lt;unistd.h&gt;\n#include &lt;sys\/socket.h&gt;\n#include &lt;bluetooth\/bluetooth.h&gt;\n#include &lt;bluetooth\/rfcomm.h&gt;\n\nint main(int argc, char **argv)\n{\n    struct sockaddr_rc addr = { 0 };\n    int s, status;\n    char dest[18] = \"01:23:45:67:89:AB\";\n\n    <em>\/\/ allocate a socket<\/em>\n    s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);\n\n    <em>\/\/ set the connection parameters (who to connect to)<\/em>\n    addr.rc_family = AF_BLUETOOTH;\n    addr.rc_channel = (uint8_t) 1;\n    str2ba( dest, &amp;addr.rc_bdaddr );\n\n    <em>\/\/ connect to server<\/em>\n    status = connect(s, (struct sockaddr *)&amp;addr, sizeof(addr));\n\n    <em>\/\/ send a message<\/em>\n    if( status == 0 ) {\n        status = write(s, \"hello!\", 6);\n    }\n\n    if( status &lt; 0 ) perror(\"uh oh\");\n\n    close(s);\n    return 0;\n}\n<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>\u9700\u8981\u6ce8\u610f\u7684\u662f\u84dd\u7259\u8fde\u63a5\u4f7f\u7528\u7684\u662f\u5c0f\u7aef\u5e8f\u800c\u4e0d\u662f\u50cf\u666e\u901aTCP\/IP\u7f51\u7edc\u90a3\u6837\u4f7f\u7528\u5927\u7aef\u5e8f\u3002<\/strong><\/li><li><em>setsockopt<\/em>\u8fd9\u79cd\u7528\u4e8e\u8bbe\u7f6eTCP\u8fde\u63a5\u9ad8\u7ea7\u9009\u9879\u7684\u51fd\u6570\u5bf9\u4e8e\u84dd\u7259\u6765\u8bf4\u662f\u6ca1\u6709\u610f\u4e49\u7684\u3002<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"l2cap%E8%BF%9E%E6%8E%A5\"><span class=\"ez-toc-section\" id=\"L2CAP%E8%BF%9E%E6%8E%A5\"><\/span>L2CAP\u8fde\u63a5<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>\u670d\u52a1\u5668\u7a0b\u5e8f\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">\n\n#include &lt;stdio.h&gt;\n#include &lt;string.h&gt;\n#include &lt;sys\/socket.h&gt;\n#include &lt;bluetooth\/bluetooth.h&gt;\n#include &lt;bluetooth\/l2cap.h&gt;\n\nint main(int argc, char **argv)\n{\n    struct sockaddr_l2 loc_addr = { 0 }, rem_addr = { 0 };\n    char buf[1024] = { 0 };\n    int s, client, bytes_read;\n    socklen_t opt = sizeof(rem_addr);\n\n    <em>\/\/ allocate socket<\/em>\n    s = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);\n\n    <em>\/\/ bind socket to port 0x1001 of the first available <\/em>\n    <em>\/\/ bluetooth adapter<\/em>\n    loc_addr.l2_family = AF_BLUETOOTH;\n    loc_addr.l2_bdaddr = *BDADDR_ANY;\n    loc_addr.l2_psm = htobs(0x1001);\n\n    bind(s, (struct sockaddr *)&amp;loc_addr, sizeof(loc_addr));\n\n    <em>\/\/ put socket into listening mode<\/em>\n    listen(s, 1);\n\n    <em>\/\/ accept one connection<\/em>\n    client = accept(s, (struct sockaddr *)&amp;rem_addr, &amp;opt);\n\n    ba2str( &amp;rem_addr.l2_bdaddr, buf );\n    fprintf(stderr, \"accepted connection from %s\\n\", buf);\n\n    memset(buf, 0, sizeof(buf));\n\n    <em>\/\/ read data from the client<\/em>\n    bytes_read = read(client, buf, sizeof(buf));\n    if( bytes_read &gt; 0 ) {\n        printf(\"received [%s]\\n\", buf);\n    }\n\n    <em>\/\/ close connection<\/em>\n    close(client);\n    close(s);\n}\n<\/code><\/pre>\n\n\n\n<p>\u5ba2\u6237\u7aef\u7a0b\u5e8f\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">nclude &lt;stdio.h&gt;\n#include &lt;string.h&gt;\n#include &lt;sys\/socket.h&gt;\n#include &lt;bluetooth\/bluetooth.h&gt;\n#include &lt;bluetooth\/l2cap.h&gt;\n\nint main(int argc, char **argv)\n{\n    struct sockaddr_l2 addr = { 0 };\n    int s, status;\n    char *message = \"hello!\";\n    char dest[18] = \"01:23:45:67:89:AB\";\n\n    if(argc &lt; 2)\n    {\n        fprintf(stderr, \"usage: %s &lt;bt_addr&gt;\\n\", argv[0]);\n        exit(2);\n    }\n\n    strncpy(dest, argv[1], 18);\n\n    <em>\/\/ allocate a socket<\/em>\n    s = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);\n\n    <em>\/\/ set the connection parameters (who to connect to)<\/em>\n    addr.l2_family = AF_BLUETOOTH;\n    addr.l2_psm = htobs(0x1001);\n    str2ba( dest, &amp;addr.l2_bdaddr );\n\n    <em>\/\/ connect to server<\/em>\n    status = connect(s, (struct sockaddr *)&amp;addr, sizeof(addr));\n\n    <em>\/\/ send a message<\/em>\n    if( status == 0 ) {\n        status = write(s, \"hello!\", 6);\n    }\n\n    if( status &lt; 0 ) perror(\"uh oh\");\n\n    close(s);\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"%E4%BD%BF%E7%94%A8sdp\"><span class=\"ez-toc-section\" id=\"%E4%BD%BF%E7%94%A8SDP\"><\/span>\u4f7f\u7528SDP<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>\u5bfb\u627e\u5177\u6709\u6307\u5b9aUUID\u7684\u670d\u52a1\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">#include &lt;bluetooth\/bluetooth.h&gt;\n#include &lt;bluetooth\/sdp.h&gt;\n#include &lt;bluetooth\/sdp_lib.h&gt;\n\nint main(int argc, char **argv)\n{\n    uint8_t svc_uuid_int[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \n        0, 0, 0xab, 0xcd };\n    uuid_t svc_uuid;\n    int err;\n    bdaddr_t target;\n    sdp_list_t *response_list = NULL, *search_list, *attrid_list;\n    sdp_session_t *session = 0;\n\n    str2ba( \"01:23:45:67:89:AB\", &amp;target );\n\n    <em>\/\/ connect to the SDP server running on the remote machine<\/em>\n    session = sdp_connect( BDADDR_ANY, &amp;target, SDP_RETRY_IF_BUSY );\n\n    <em>\/\/ specify the UUID of the application we're searching for<\/em>\n    sdp_uuid128_create( &amp;svc_uuid, &amp;svc_uuid_int );\n    search_list = sdp_list_append( NULL, &amp;svc_uuid );\n\n    <em>\/\/ specify that we want a list of all the matching applications' attributes<\/em>\n    uint32_t range = 0x0000ffff;\n    attrid_list = sdp_list_append( NULL, &amp;range );\n\n    <em>\/\/ get a list of service records that have UUID 0xabcd<\/em>\n    err = sdp_service_search_attr_req( session, search_list, \\\n            SDP_ATTR_REQ_RANGE, attrid_list, &amp;response_list);\n    .\n    .\n<\/code><\/pre>\n\n\n\n<p>\u89e3\u6790\u641c\u5bfb\u7ed3\u679c\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">    sdp_list_t *r = response_list;\n\n    <em>\/\/ go through each of the service records<\/em>\n    for (; r; r = r-&gt;next ) {\n        sdp_record_t *rec = (sdp_record_t*) r-&gt;data;\n        sdp_list_t *proto_list;\n        \n        <em>\/\/ get a list of the protocol sequences<\/em>\n        if( sdp_get_access_protos( rec, &amp;proto_list ) == 0 ) {\n        sdp_list_t *p = proto_list;\n\n        <em>\/\/ go through each protocol sequence<\/em>\n        for( ; p ; p = p-&gt;next ) {\n            sdp_list_t *pds = (sdp_list_t*)p-&gt;data;\n\n            <em>\/\/ go through each protocol list of the protocol sequence<\/em>\n            for( ; pds ; pds = pds-&gt;next ) {\n\n                <em>\/\/ check the protocol attributes<\/em>\n                sdp_data_t *d = (sdp_data_t*)pds-&gt;data;\n                int proto = 0;\n                for( ; d; d = d-&gt;next ) {\n                    switch( d-&gt;dtd ) { \n                        case SDP_UUID16:\n                        case SDP_UUID32:\n                        case SDP_UUID128:\n                            proto = sdp_uuid_to_proto( &amp;d-&gt;val.uuid );\n                            break;\n                        case SDP_UINT8:\n                            if( proto == RFCOMM_UUID ) {\n                                printf(\"rfcomm channel: %d\\n\",d-&gt;val.int8);\n                            }\n                            break;\n                    }\n                }\n            }\n            sdp_list_free( (sdp_list_t*)p-&gt;data, 0 );\n        }\n        sdp_list_free( proto_list, 0 );\n\n        }\n\n        printf(\"found service record 0x%x\\n\", rec-&gt;handle);\n        sdp_record_free( rec );\n    }\n\n    sdp_close(session);\n}\n<\/code><\/pre>\n\n\n\n<p>\u63cf\u8ff0\u670d\u52a1\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">#include &lt;bluetooth\/bluetooth.h&gt;\n#include &lt;bluetooth\/sdp.h&gt;\n#include &lt;bluetooth\/sdp_lib.h&gt;\n\nsdp_session_t *register_service()\n{\n    uint32_t service_uuid_int[] = { 0, 0, 0, 0xABCD };\n    uint8_t rfcomm_channel = 11;\n    const char *service_name = \"Roto-Rooter Data Router\";\n    const char *service_dsc = \"An experimental plumbing router\";\n    const char *service_prov = \"Roto-Rooter\";\n\n    uuid_t root_uuid, l2cap_uuid, rfcomm_uuid, svc_uuid;\n    sdp_list_t *l2cap_list = 0, \n               *rfcomm_list = 0,\n               *root_list = 0,\n               *proto_list = 0, \n               *access_proto_list = 0;\n    sdp_data_t *channel = 0, *psm = 0;\n\n    sdp_record_t *record = sdp_record_alloc();\n\n    <em>\/\/ set the general service ID<\/em>\n    sdp_uuid128_create( &amp;svc_uuid, &amp;service_uuid_int );\n    sdp_set_service_id( record, svc_uuid );\n\n    <em>\/\/ make the service record publicly browsable<\/em>\n    sdp_uuid16_create(&amp;root_uuid, PUBLIC_BROWSE_GROUP);\n    root_list = sdp_list_append(0, &amp;root_uuid);\n    sdp_set_browse_groups( record, root_list );\n\n    <em>\/\/ set l2cap information<\/em>\n    sdp_uuid16_create(&amp;l2cap_uuid, L2CAP_UUID);\n    l2cap_list = sdp_list_append( 0, &amp;l2cap_uuid );\n    proto_list = sdp_list_append( 0, l2cap_list );\n\n    <em>\/\/ set rfcomm information<\/em>\n    sdp_uuid16_create(&amp;rfcomm_uuid, RFCOMM_UUID);\n    channel = sdp_data_alloc(SDP_UINT8, &amp;rfcomm_channel);\n    rfcomm_list = sdp_list_append( 0, &amp;rfcomm_uuid );\n    sdp_list_append( rfcomm_list, channel );\n    sdp_list_append( proto_list, rfcomm_list );\n\n    <em>\/\/ attach protocol information to service record<\/em>\n    access_proto_list = sdp_list_append( 0, proto_list );\n    sdp_set_access_protos( record, access_proto_list );\n\n    <em>\/\/ set the name, provider, and description<\/em>\n    sdp_set_info_attr(record, service_name, service_prov, service_dsc);\n    .\n    .\n\n<\/code><\/pre>\n\n\n\n<p>\u6ce8\u518c\u670d\u52a1\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">    .\n    .\n    int err = 0;\n    sdp_session_t *session = 0;\n\n    <em>\/\/ connect to the local SDP server, register the service record, and <\/em>\n    <em>\/\/ disconnect<\/em>\n    session = sdp_connect( BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY );\n    err = sdp_record_register(session, record, 0);\n\n    <em>\/\/ cleanup<\/em>\n    sdp_data_free( channel );\n    sdp_list_free( l2cap_list, 0 );\n    sdp_list_free( rfcomm_list, 0 );\n    sdp_list_free( root_list, 0 );\n    sdp_list_free( access_proto_list, 0 );\n\n    return session;\n}<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>\u53c2\u8003\u6765\u6e90 \u4ee5\u53ca\u901a\u8fc7Google\u3001\u767e\u5ea6\u67e5\u5230\u7684\u5176\u4ed6\u8d44\u6599 \u84dd\u7259 \u63d0\u51fa\u8005 1998\u5e74\uff0c\u7231\u7acb\u4fe1\u3001\u8bfa\u57fa\u4e9a\u3001\u4e1c\u829d\u3001IBM\u3001Intel\u3002 \u540d\u5b57\u7531\u6765 \u84dd\u7259\u6280\u672f\u7edf\u4e00\u4e86\u6807\u51c6\u4e0d\u4e00\u7684\u77ed\u8ddd\u79bb\u65e0\u7ebf\u4f20\u8f93\u6280\u672f\uff0c\u5c31\u5982\u540cHarald Bl&#46;&#46;&#46;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[10],"tags":[110],"class_list":["post-974","post","type-post","status-publish","format-standard","hentry","category-10","tag-bluetooth"],"_links":{"self":[{"href":"https:\/\/blog.cauchyschwarz.com\/index.php?rest_route=\/wp\/v2\/posts\/974","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.cauchyschwarz.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.cauchyschwarz.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.cauchyschwarz.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.cauchyschwarz.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=974"}],"version-history":[{"count":1,"href":"https:\/\/blog.cauchyschwarz.com\/index.php?rest_route=\/wp\/v2\/posts\/974\/revisions"}],"predecessor-version":[{"id":975,"href":"https:\/\/blog.cauchyschwarz.com\/index.php?rest_route=\/wp\/v2\/posts\/974\/revisions\/975"}],"wp:attachment":[{"href":"https:\/\/blog.cauchyschwarz.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=974"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.cauchyschwarz.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=974"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.cauchyschwarz.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=974"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}