Socket:套接字,就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。

TCP:传输控制协议(Transmission Control Protocol),是一种面向连接的、可靠的、基于字节流的传输层通信协议。

在通过WiFi连接并控制小车案例中,实现控制功能的其中一个方案就是通过创建Socket,基于TCP进行字节数据的发送。下面是我在Deveco中基于TCP的对多个设备的tcp连接实现的分享。

1.权限引入

在写tcp的相关代码之前,我们需要先在module.json5文件中申请网络权限

2.代码具体实现

1)创建代码文件Tcp.est,用于代码存放

2)定义类对象TCPSocketServerSingleton,用以创建socket、连接设备和发送信息。

class TCPSocketServerSingleton {
private static instance: TCPSocketServerSingleton;
private tcp: socket.TCPSocket;
private connected: boolean = false;

// 连接配置 - 改为可配置
private bindAddr: socket.NetAddress = {
  address: "192.168.1.1",  // 默认IP,可以在连接时修改
  port: 8080
};

private tcp_connect_options: socket.TCPConnectOptions = {
  address: this.bindAddr,// 连接地址
  timeout: 2000
};

private tcp_send_Options: socket.TCPSendOptions = {
  data: ''       // 发送的数据内容
};

private constructor() {
  this.tcp = socket.constructTCPSocketInstance();   // 创建TCP Socket实例
  this.setupEventListeners();// 设置事件监听器
}
//单设备模式
public static getInstance(): TCPSocketServerSingleton {
  if (!TCPSocketServerSingleton.instance) {
    TCPSocketServerSingleton.instance = new TCPSocketServerSingleton();
  }
  return TCPSocketServerSingleton.instance;
}

// 创建新的独立实例,用于需要多个TCP连接的场景
public static createNewInstance(): TCPSocketServerSingleton {
  return new TCPSocketServerSingleton();//返回新对象
}
// 设置连接地址
public setAddress(ip: string, port: number): void {
  this.bindAddr = {
    address: ip,
    port: port
  };
  this.tcp_connect_options = {
    address: this.bindAddr,
    timeout: 2000
  };
}
// 连接服务器
public async connect(ip?: string, port?: number): Promise<boolean> {
  if (ip && port) {
    this.setAddress(ip, port);
  }

  return new Promise((resolve) => {
    this.tcp.connect(this.tcp_connect_options).then(() => {
      this.connected = true;
      console.log("连接成功");
      resolve(true);
    }).catch((error: BusinessError) => {
      console.error('连接错误:', error);
      this.connected = false;
      resolve(false);
    });
  });
}
private setupEventListeners() {
  this.tcp.on('message', (value: SocketInfo) => {
    console.log("收到消息");
    let buffer = value.message;
    let dataView = new DataView(buffer);
    let str = "";
    for (let i = 0; i < dataView.byteLength; ++i) {
      str += String.fromCharCode(dataView.getUint8(i));
    }
    console.log("收到数据:" + str);
  });

  this.tcp.on('connect', () => {
    console.log("连接建立");
    this.connected = true;
  });

  this.tcp.on('close', () => {
    console.log("连接关闭");
    this.connected = false;
  });

  this.tcp.on('error', (error: BusinessError) => {
    console.error("Socket错误:", error);
    this.connected = false;
  });
}
// 发送数据
public Send_data(message: string): boolean {
  if (!this.connected) {
    console.error("未连接,无法发送数据");
    return false;
  }

  this.tcp_send_Options.data = message;
  console.log("发送: " + message);

  this.tcp.send(this.tcp_send_Options).then(() => {
    console.log("发送成功");
  }).catch((error: BusinessError) => {
    console.error('发送数据错误:', error);
  });

  return true;
}

// 断开连接
public disconnect(): void {
  this.tcp.close();
  this.connected = false;
}

// 获取连接状态
public isConnected(): boolean {
  return this.connected;
}
}

3)在主页面中,我们可以调用设置的各种函数来实现应用和设备之间的连接

@State LedIP1: string = '192.168.43.100';
@State LedIP2: string = '192.168.43.101';
@State LedPort: number = 8080;
private tcpClient1 = TCPSocketServerSingleton.createNewInstance();
private tcpClient2 = TCPSocketServerSingleton.createNewInstance();
// 连接设备
private async connectToLed(): Promise<void> {
  this.isConnecting = true;

  try {
    // 设置TCP客户端地址
    this.tcpClient1.setAddress(this.LedIP1, this.LedPort);
    this.tcpClient2.setAddress(this.LedIP2, this.LedPort);

    // 开始连接
    const success1 = await this.tcpClient1.connect();
    const success2 = await this.tcpClient2.connect();

    if (success1&&success2) {
      prompt.showToast({
        message: '连接成功!',
        duration: 2000
      });
      this.isConnected = true;
    } else {
      prompt.showToast({
        message: '连接失败,请检查IP和端口',
        duration: 3000
      });
    }
  } catch (error) {
    console.error('连接错误:', error);
    prompt.showToast({
      message: '连接异常',
      duration: 2000
    });
  } finally {
    this.isConnecting = false;
  }

  // console.log(`发送指令: ${"Love_Your_Life"}`);
  // this.tcpClient1.Send_data("Love_Your_Life");
  // this.tcpClient2.Send_data("Love_Your_Life");
}

然后给按钮或者文本设置点击事件,触发时调用Send_data()向tcp连接到的设备发送设置好的指令即可。

Text("如果你觉得很疲惫,那就休息一下吧,我永远会为你亮一盏灯")
  .fontStyle(FontStyle.Italic)
  .onClick(() => {
    this.connectToLed();
    this.tcpClient1.Send_data("Love_Your_Life");
    this.tcpClient2.Send_data("Love_Your_Life");
    this.showPopup = true;
  })

注:事实上在发送数据之前还有连接步骤,需要我们寻找设备连接热点时随机分配到的IP,并输入应用中用setAddress()更新IP和端口。但是由于我提前设置了IP预分配方案,已经指定并保存好了相应的IP和端口,所以无需重新寻找IP即可实现直接连接,如connectToLed()代码所示。

3.总结

基于Tcp的多设备连接实现是一个相对复杂的过程,需要考虑IP的寻找、新对象的创建、连接状态的管理和指令的设置等多种因素,对于初学者来说尤为困难。本帖仅作最简单案例的实现与分享(因为我也是初学者,笑.jpg)。最后提醒,在实现IP预存方案之前先去了解网络连接及热点IP分配等内容(比如DHCP),否则在连接过程中乱设置IP,十有八九是2连接不上的。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐