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