• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# SPP-based Connection and Data Transmission
2
3## Introduction
4This document provides guidance on how to connect devices and transfer data via Serial Port Profile (SPP). When two devices communicate via SPP, they can be distinguished as client and server based on their respective functions. This guide describes the implementation methods for both the client and server.
5
6## How to Implement
7After obtaining the server's device address, the client can initiate a connection to the specific UUID of the server. The server's device address can be obtained through the device discovery process. For details, see [Bluetooth Discovery Development](br-discovery-development-guide.md). Once the connection between the two ends is successfully established, the client can send data to the server or receive data from the server.
8
9The server needs to support the UUID service for client connections and maintain listening for connection status changes. After the connection between the two ends is successfully established, the server can receive data from the client or send data to the client.
10
11Both the client and the server can actively disconnect. The application needs to determine which end performs the disconnection.
12
13## How to Develop
14
15### Applying for Required Permissions
16Apply for the **ohos.permission.ACCESS_BLUETOOTH** permission. For details about how to configure and apply for permissions, see [Declaring Permissions](../../security/AccessToken/declare-permissions.md) and [Requesting User Authorization](../../security/AccessToken/request-user-authorization.md).
17
18### Importing Required Modules
19Import the related modules.
20```ts
21import { socket } from '@kit.ConnectivityKit';
22import { BusinessError } from '@kit.BasicServicesKit';
23```
24
25### Client
26
27#### 1. Initiating a Connection
28The client can initiate a connection after searching for the target device through the device discovery process. The UUID service to be connected to must be consistent with the UUID service constructed when the server creates the socket. During the connection process, the Bluetooth subsystem will check whether the server supports this UUID service; if not, the connection will fail. Therefore, the application must ensure that the target device supports the required UUID service; otherwise, the connection initiated will be invalid.
29```ts
30// Obtain the device address through the device discovery process.
31let peerDevice = 'XX:XX:XX:XX:XX:XX';
32
33// Define the client socket ID.
34let clientNumber = -1;
35
36// Configure connection parameters.
37let option: socket.SppOptions = {
38  uuid: '00009999-0000-1000-8000-00805F9B34FB', // The UUID service to be connected must be supported by the server.
39  secure: false,
40  type: socket.SppType.SPP_RFCOMM
41};
42console.info('startConnect ' + peerDevice);
43socket.sppConnect(peerDevice, option, (err, num: number) => {
44  if (err) {
45    console.error('startConnect errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
46  } else {
47    console.info('startConnect clientNumber: ' + num);
48    clientNumber = num;
49  }
50});
51console.info('startConnect after ' + peerDevice);
52```
53
54#### 2. Transmitting Data
55
56**2.1 Sending Data**<br>
57After the connection between the client and server is established, the client can send data to the server.
58```ts
59let clientNumber = 1; // Note: The value is the client socket ID in the asynchronous callback returned when the client initiates a connection. The ID here is a pseudo-code ID.
60let arrayBuffer = new ArrayBuffer(2);
61let data = new Uint8Array(arrayBuffer);
62data[0] = 3;
63data[1] = 4;
64try {
65  socket.sppWrite(clientNumber, arrayBuffer);
66} catch (err) {
67  console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
68}
69```
70
71**2.2 Receiving Data**<br>
72After the connection between the client and server is established, the client can receive data from the server. This is implemented through [socket.on('sppRead ')](../../reference/apis-connectivity-kit/js-apis-bluetooth-socket.md#socketonsppread).
73```ts
74let clientNumber = 1; // Note: The value is the client socket ID in the asynchronous callback returned when the client initiates a connection. The ID here is a pseudo-code ID.
75
76// Define the callback for data read events.
77function read(dataBuffer: ArrayBuffer) {
78  let data = new Uint8Array(dataBuffer);
79  console.info('client data: ' + JSON.stringify(data));
80}
81
82try {
83  // Enable listening for data read events.
84  socket.on('sppRead', clientNumber, read);
85} catch (err) {
86  console.error('readData errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
87}
88```
89
90#### 3. Terminating the Connection
91When an application no longer needs an established connection, it can proactively disconnect from the client. Before that, you need to disable listening for data read events.
92```ts
93let clientNumber = 1; // Note: The value is the client socket ID in the asynchronous callback returned when the client initiates a connection. The ID here is a pseudo-code ID.
94
95// Define the callback for data read events.
96function read(dataBuffer: ArrayBuffer) {
97  let data = new Uint8Array(dataBuffer);
98  console.info('client data: ' + JSON.stringify(data));
99}
100
101try {
102  // Disable listening for data read events.
103  socket.off('sppRead', clientNumber, read);
104} catch (err) {
105  console.error('off sppRead errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
106}
107try {
108  // Disconnect from the client.
109  socket.sppCloseClientSocket(clientNumber);
110} catch (err) {
111  console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
112}
113```
114
115### Server
116
117#### 1. Create a server socket.
118The server needs to register the specified UUID service in the Bluetooth subsystem by creating a socket. The UUID service can be named freely, such as using the application name. When a client sends a connection request, it includes a UUID to specify the target service. Connection establishment is permitted only when the server's and client's UUIDs are identical.
119```ts
120// Define the server socket ID.
121let serverNumber = -1;
122
123// Set listening parameters.
124let option: socket.SppOptions = {
125  uuid: '00009999-0000-1000-8000-00805F9B34FB',
126  secure: false,
127  type: socket.SppType.SPP_RFCOMM
128};
129
130// Create a listening socket on the server. The UUID service is registered in the Bluetooth subsystem.
131socket.sppListen("demonstration", option, (err, num: number) => {
132  if (err) {
133    console.error('sppListen errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
134  } else {
135    console.info('sppListen serverNumber: ' + num);
136    serverNumber = num;
137  }
138});
139```
140
141#### 2. Enable listening for client connections.
142After the server socket is created, the server can listen for client connections. When a connection request is received, the server obtains the socket ID of the client. At this time, the connection between the server and client is successfully established.
143```ts
144let serverNumber = 1; // Note: The value is the server socket ID in the asynchronous callback returned when the server socket is created. The ID here is a pseudo-code ID.
145
146// Define the client socket ID.
147let clientNumber = -1;
148
149socket.sppAccept(serverNumber, (err, num: number) => {
150  if (err) {
151    console.error('accept errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
152  } else {
153    console.info('accept clientNumber: ' + num);
154    clientNumber = num;
155  }
156});
157```
158
159#### 3. Transmitting Data
160
161**3.1 Sending Data**<br>
162After the connection between the server and client is established, the server can send data to the client.
163```ts
164let clientNumber = 1; // Note: The value is the client socket ID in the asynchronous callback returned when the server listens for a client connection. The ID here is a pseudo-code ID.
165
166let arrayBuffer = new ArrayBuffer(2);
167let data = new Uint8Array(arrayBuffer);
168data[0] = 9;
169data[1] = 8;
170try {
171  socket.sppWrite(clientNumber, arrayBuffer);
172} catch (err) {
173  console.error('sppWrite errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
174}
175```
176
177**3.2 Receiving Data**<br>
178After the connection between the server and client is established, the server can receive data from the client. This is implemented through [socket.on('sppRead ')](../../reference/apis-connectivity-kit/js-apis-bluetooth-socket.md#socketonsppread).
179```ts
180let clientNumber = 1; // Note: This value is the client socket ID obtained by the asynchronous callback when the server listens to the connection. This is a pseudo code ID.
181
182// Define the callback for data read events.
183read(dataBuffer: ArrayBuffer) {
184  let data = new Uint8Array(dataBuffer);
185  console.info('client data: ' + JSON.stringify(data));
186}
187
188try {
189  // Enable listening for data read events.
190  socket.on('sppRead', clientNumber, this.read);
191} catch (err) {
192  console.error('readData errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
193}
194```
195#### 4. Terminating the Connection
196When an application no longer needs an established connection, it can proactively disconnect from the server.
197
198- Before that, you need to disable listening for data read events.
199```ts
200let clientNumber = 1; // Note: This value is the client socket ID obtained by the asynchronous callback when the server listens to the connection. This is a pseudo code ID.
201
202// Define the callback for data read events.
203function read(dataBuffer: ArrayBuffer) {
204  let data = new Uint8Array(dataBuffer);
205  console.info('client data: ' + JSON.stringify(data));
206}
207
208try {
209  // Disable listening for data read events.
210  socket.off('sppRead', clientNumber, read);
211} catch (err) {
212  console.error('off sppRead errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
213}
214try {
215  // Disconnect from the server.
216  socket.sppCloseClientSocket(this.clientNumber);
217} catch (err) {
218  console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
219}
220```
221
222#### 5. Deleting the Server Socket
223When the application no longer needs the server socket, it needs to proactively close the socket. The Bluetooth subsystem then deletes the corresponding UUID service registered earlier. If the client initiates a connection at this time, the connection fails.
224
225- The application can also disconnect from the server when deleting the socket. Before that, the application needs to disable listening for data read events.
226```ts
227let serverNumber = 1; // Note: The value is the server socket ID in the asynchronous callback returned when the server socket is created. The ID here is a pseudo-code ID.
228
229// Define the callback for data read events.
230function read(dataBuffer: ArrayBuffer) {
231  let data = new Uint8Array(dataBuffer);
232  console.info('client data: ' + JSON.stringify(data));
233}
234
235try {
236  // Disable listening for data read events.
237  socket.off('sppRead', clientNumber, read);
238} catch (err) {
239  console.error('off sppRead errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
240}
241
242try {
243  // If the application no longer needs the server socket, proactively delete it.
244  socket.sppCloseServerSocket(serverNumber);
245} catch (err) {
246  console.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
247}
248```
249
250## Complete Sample Code
251
252### Client
253```ts
254import { socket } from '@kit.ConnectivityKit'
255import { BusinessError } from '@kit.BasicServicesKit';
256
257class SppClientManager {
258  // Define the client socket ID.
259  clientNumber: number = -1;
260
261  // Initiate a connection.
262  public startConnect(peerDevice: string): void {
263    // Configure connection parameters.
264    let option: socket.SppOptions = {
265      uuid: '00009999-0000-1000-8000-00805F9B34FB', // The UUID service to be connected must be supported by the server.
266      secure: false,
267      type: socket.SppType.SPP_RFCOMM
268    };
269    console.info('startConnect ' + peerDevice);
270    socket.sppConnect(peerDevice, option, (err, num: number) => {
271      if (err) {
272        console.error('startConnect errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
273      } else {
274        console.info('startConnect clientNumber: ' + num);
275        this.clientNumber = num;
276      }
277    });
278    console.info('startConnect after ' + peerDevice);
279  }
280
281  // Send data.
282  public sendData() {
283    console.info('sendData ' + this.clientNumber);
284    let arrayBuffer = new ArrayBuffer(2);
285    let data = new Uint8Array(arrayBuffer);
286    data[0] = 3;
287    data[1] = 4;
288    try {
289      socket.sppWrite(this.clientNumber, arrayBuffer);
290    } catch (err) {
291      console.error('sppWrite errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
292    }
293  }
294
295  // Define the callback for data read events.
296  read = (dataBuffer: ArrayBuffer) => {
297    let data = new Uint8Array(dataBuffer);
298    console.info('client data: ' + JSON.stringify(data));
299  };
300
301  // Read data.
302  public readData() {
303    try {
304      // Enable listening for data read events.
305      socket.on('sppRead', this.clientNumber, this.read);
306    } catch (err) {
307      console.error('readData errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
308    }
309  }
310
311  // Terminate the connection.
312  public stopConnect() {
313    console.info('closeSppClient ' + this.clientNumber);
314    try {
315      // Disable listening for data read events.
316      socket.off('sppRead', this.clientNumber, this.read);
317    } catch (err) {
318      console.error('off sppRead errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
319    }
320    try {
321      // Disconnect from the client.
322      socket.sppCloseClientSocket(this.clientNumber);
323    } catch (err) {
324      console.error('stopConnect errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
325    }
326  }
327}
328
329let sppClientManager = new SppClientManager();
330export default sppClientManager as SppClientManager;
331```
332
333### Server
334```ts
335import { socket } from '@kit.ConnectivityKit'
336import { BusinessError } from '@kit.BasicServicesKit';
337
338class SppServerManager {
339  serverNumber: number = -1;
340  clientNumber: number = -1;
341
342  // Create a listening socket on the server.
343  public startListen(): void {
344    console.info('startListen');
345
346    // Set listening parameters.
347    let option: socket.SppOptions = {
348      uuid: '00009999-0000-1000-8000-00805F9B34FB',
349      secure: false,
350      type: socket.SppType.SPP_RFCOMM
351    };
352
353    // Create a listening socket on the server. The UUID service is registered in the Bluetooth subsystem.
354    socket.sppListen("demonstration", option, (err, num: number) => {
355      if (err) {
356        console.error('sppListen errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
357      } else {
358        console.info('sppListen serverNumber: ' + num);
359        this.serverNumber = num;
360      }
361    });
362  }
363
364  // Enable listening for connection requests and wait for connections.
365  public accept() {
366    console.info('accept ' + this.serverNumber);
367    socket.sppAccept(this.serverNumber, (err, num: number) => {
368      if (err) {
369        console.error('accept errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
370      } else {
371        console.info('accept clientNumber: ' + num);
372        this.clientNumber = num;
373      }
374    });
375  }
376
377  // Send data.
378  public sendData() {
379    console.info('sendData serverNumber: ' + this.serverNumber + ' clientNumber: ' + this.clientNumber);
380    let arrayBuffer = new ArrayBuffer(2);
381    let data = new Uint8Array(arrayBuffer);
382    data[0] = 9;
383    data[1] = 8;
384    try {
385      socket.sppWrite(this.clientNumber, arrayBuffer);
386    } catch (err) {
387      console.error('sppWrite errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
388    }
389  }
390
391  // Define the callback for data read events.
392  read = (dataBuffer: ArrayBuffer) => {
393    let data = new Uint8Array(dataBuffer);
394    console.info('client data: ' + JSON.stringify(data));
395  };
396
397  // Read data.
398  public readData() {
399    try {
400      // Enable listening for data read events.
401      socket.on('sppRead', this.clientNumber, this.read);
402    } catch (err) {
403      console.error('readData errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
404    }
405  }
406
407  // Terminate the connection.
408  public stopConnect() {
409    console.info('stopConnect');
410    try {
411      // Disable listening for data read events.
412      socket.off('sppRead', this.clientNumber, this.read);
413    } catch (err) {
414      console.error('off sppRead errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
415    }
416    try {
417      // Disconnect from the server.
418      socket.sppCloseClientSocket(this.clientNumber);
419    } catch (err) {
420      console.error('stopConnect errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
421    }
422  }
423
424  // Close the server socket.
425  public closeSppServer() {
426    console.info('closeSppServer');
427    try {
428      // If the application no longer needs the server socket, proactively delete it.
429      socket.sppCloseServerSocket(this.serverNumber);
430    } catch (err) {
431      console.error('sppCloseServerSocket errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
432    }
433  }
434}
435
436let sppServerManager = new SppServerManager();
437export default sppServerManager as SppServerManager;
438```
439