鸿蒙本地模拟器 模拟TCP服务端的过程

鸿蒙模拟器模拟TCP服务端的过程涉及几个关键步骤,主要包括创建TCPSocketServer实例、绑定IP地址和端口、监听连接请求、接收和发送数据以及处理连接事件。以下是详细的模拟过程:

**1.创建TCPSocketServer实例:**首先,需要导入鸿蒙的socket模块,并创建一个TCPSocketServer对象。这个对象将用于管理TCP连接。

**2.绑定IP地址和端口:**通过调用listen()方法,将TCPSocketServer实例绑定到本地IP地址和端口上。这样,服务端就可以监听指定端口上的连接请求。

**3.监听连接请求:**服务端通过订阅TCPSocketServer的connect事件来监听客户端的连接请求。当客户端尝试连接时,服务端会接收到一个连接事件。

**4.接收和发送数据:**一旦客户端和服务端建立连接,服务端会返回一个TCPSocketConnection对象,用于与客户端进行数据通信。服务端可以通过订阅TCPSocketConnection的message事件来接收客户端发送的数据,并通过调用send()方法来向客户端发送数据。

**5.处理连接事件:**服务端还需要处理其他事件,如close和error,以管理连接的生命周期和错误处理。

**6.UI效果展示:**在模拟器上,服务端接收到的控制命令可以通过UI界面展示。例如,当客户端发送一个"开灯"命令时,服务端的UI界面会相应地更新灯的状态,或者通过改变颜色或显示图片来模拟灯的开启。

**7.端口映射和转发:**为了使服务端能够在模拟器上正确地与外部客户端通信,可能需要进行端口映射和转发。这通常通过命令行工具如netsh或鸿蒙的HDC命令来实现,将模拟器的端口映射到主机的端口上。

上诉步骤中,1-6的步骤可以根据开发者文档的TCP服务端实现操作,并且直接通过本地模拟器运行项目即可。例如以下案例:

/**
 * 1.导入 socket 模块
 */
import { socket } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';

/**
 * 2.创建 TCPSocketServer
 * 创建一个 TCPSocketServer 连接,返回一个 TCPSocketServer 对象。
 */
let tcpServer: socket.TCPSocketServer = socket.constructTCPSocketServerInstance();

class SocketInfo {
  message: ArrayBuffer = new ArrayBuffer(1);
  remoteInfo: socket.SocketRemoteInfo = {} as socket.SocketRemoteInfo;
}

@Entry
@Component
struct Index {
  @State showDatas: string[] = [] //用于接收客服端发送的消息
  @State serverLocalIp: string = '127.0.0.1'
  @State serverPort: number = 8000
  @State serverData:string = '服务端发送的信息'
  private connectState: boolean = false
  private tcpSocketConnection ?: socket.TCPSocketConnection

  async listenServer(serverIp: string, serverPort: number) {
    let ipAddress: socket.NetAddress = {
      address: serverIp,
      port: serverPort,
    }
    // 绑定IP:Port、监听并启动服务,接收客户端的连接请求
    tcpServer.listen(ipAddress).then(() => {
      console.info('===listen success===');
      tcpServer.on("connect", (tcpConnection: socket.TCPSocketConnection) => {
        console.info("===connect success====")
        this.connectState = true
        this.tcpSocketConnection = tcpConnection

        tcpConnection.on("message", (data: SocketInfo) => {
          console.info("====receive message====")
          let buffer = data.message;
          let dataView = new DataView(buffer);
          let messageData = "";
          for (let i = 0; i < dataView.byteLength; ++i) {
            messageData += String.fromCharCode(dataView.getUint8(i));
          }
          this.showDatas.push('客户端:' + messageData)
        });
        // 订阅TCPSocketConnection相关的事件
        tcpConnection.on("close", () => {
          console.info("===断开连接===");
        });
      })
    }).catch((err: BusinessError) => {
      console.info('listen fail');
    });}

  async sendData(message: string) {
    if (this.connectState) { //连接成功才可发送数据
      // 服务端给连接的客户端发送信息
      let tcpSendOptions: socket.TCPSendOptions = {} as socket.TCPSendOptions;
      tcpSendOptions.data = message
      this.tcpSocketConnection?.send(tcpSendOptions).then(() => {
        console.info('===send success===');
        this.showDatas.push('服务端:' + tcpSendOptions.data)
      })
    }
  }

  build() {
    Column({ space: 5 }) {
      Text('TCP的服务端实现')
        .fontSize(30)

      Row({ space: 5 }) {
        Text('服务端ip:')
          .width(110)
          .fontSize(20)
          .textAlign(TextAlign.End)

        TextInput({ placeholder: this.serverLocalIp })
          .fontSize(20)
          .width('60%')
          .onChange((value) => {
            this.serverLocalIp = value
          })
      }

      Row({ space: 5 }) {
        Text('服务端port:')
          .width(110)
          .fontSize(20)
          .textAlign(TextAlign.End)
        TextInput({ placeholder: this.serverPort.toString() })
          .fontSize(20)
          .width('60%')
          .type(InputType.Number)
          .onChange((value) => {
            this.serverPort = parseInt(value)
          })
      }

      Button('服务端启动并监听连接')
        .fontSize(25)
        .onClick(() => {
          this.listenServer(this.serverLocalIp, this.serverPort)
        })
      TextInput({ placeholder: this.serverData })
        .fontSize(20)
        .width('90%')
        .height(50)
        .onChange((value) => {
          this.serverData = value
        })
      Button('发送消息') //监听连接状态
        .fontSize(25)
        .onClick(()=>{
          this.sendData(this.serverData)
        })

      List(){
        ListItem(){
          Text('服务端消息展示:')
        }
        ForEach(this.showDatas, (item: string) => {
          ListItem(){
            Text(item)
              .fontSize(20)
          }
        })
      }.width('95%')
      .layoutWeight(1)
    }
  }
}

以上代码的UI效果:

因为需要使用网络,需要开通网络权限:

本地模拟器模拟TCP服务端的必备操作

IP端口映射

  1. 以管理员身份运行 命令提示符

  2. 电脑IP和本地模拟器IP端口映射

    在命令行输入以下代码,其中connectaddress=127.0.0.1 connectport=8000 必须一致

    当有服务访问"你电脑的IP:8888 "时,操作系统会自动映射到"127.0.0.1:8000"

javascript 复制代码
netsh interface portproxy add v4tov4 listenaddress=你的电脑的IP地址 listenport=8888 connectaddress=127.0.0.1 connectport=8000

显示映射结果

javascript 复制代码
netsh interface portproxy show v4tov4

设置端口转发

首先启动本地模拟器
在进行端口转发前,一定要先启动本地模拟器 ,即 本地模拟器每次重启都需要重新设备端口转发

接下来需要配置鸿蒙模拟器端口转发,使用HDC命令操作,需要用到hdc.exe文件 ,该文件在OpenHarmony SDK目录下的\toolchains目录内部找到(每个人的路径不同 ),需要记住该目录。例如我的电脑上hdc.exe的路径:

进入toolchains目录,在命令行执行以下命令进行端口转发:

注意:本地模拟器每次重启都需要重新进行端口转发

javascript 复制代码
hdc.exe -t 127.0.0.1:5555 fport tcp:8000 tcp:8000

执行以上命令,得到如下结果

最后将项目部署到模拟器上,启动服务端便可以和TCP客户端连接并且通信了!!!

相关推荐
想要打 Acm 的小周同学呀1 小时前
TCP/IP学习笔记
笔记·学习·tcp/ip·计算机网络
yuwinter2 小时前
鸿蒙HarmonyOS学习笔记(4)
笔记·学习·harmonyos
zhongcx0110 小时前
鸿蒙NEXT开发案例:随机密码生成
华为·harmonyos·鸿蒙·鸿蒙next
shaodong112310 小时前
鸿蒙HarmonyOS系统相机Camera相关API使用
华为·harmonyos·鸿蒙·相机
港股研究社10 小时前
华为Mate 70系列发布,揭示AI+消费电子产业化新阶段
人工智能·华为
途普智能10 小时前
途普科技企业知识中台完成华为昇思MindSpore技术认证
数据库·人工智能·科技·华为·知识图谱
IpdataCloud11 小时前
IP反向追踪技术,了解一下?
网络·tcp/ip·智能路由器
ZZZCY200312 小时前
华为ENSP--BGP路由协议实验详解
华为·智能路由器
楚疏笃14 小时前
鸿蒙学习统一上架与多端分发-应用分发(2)
学习·华为·harmonyos