#DAYU200体验官# Dayu200与Hi3861 TCP通信(JS) 原创 精华

Hello_Kun
发布于 2022-5-28 19:44
浏览
13收藏

@toc

0. 说明

OH系统版本:OpenHarmony3.1Release
IDE: 3.0.0.900
实现语言:JS

1. TCP JS接口

1.1 接口分析

参考地址:Socket连接
TCP通信流程:
Initial TCP ————> Bind IP ————> Connect Target IP ————> Send/Receive

  • 初始化IP相关配置:
- 引用模块: import socket from '@ohos.net.socket'
- 添加权限:ohos.permission.INTERNET、ohos.permission.GET_WIFI_INFO
- 创建对象:let tcp = socket.constructTCPSocketInstance();
  • 绑定IP与端口号
bind(address: NetAddress, callback: AsyncCallback<void>): void
绑定IP地址和端口,端口可以指定或由系统随机分配。使用callback方法作为异步方法。
需要权限:ohos.permission.INTERNET
系统能力:SystemCapability.Communication.NetStack
示例:
let tcp = socket.constructTCPSocketInstance();
tcp.bind({address: '192.168.xx.xxx', port: xxxx, family: 1}, err => {
  if (err) {
	console.log('bind fail');
	return;
  }
  console.log('bind success');
})
  • 连接目标IP
connect(options: TCPConnectOptions, callback: AsyncCallback<void>): void
连接到指定的IP地址和端口。使用callback方法作为异步方法。
需要权限:ohos.permission.INTERNET
系统能力:SystemCapability.Communication.NetStack
示例:
let tcp = socket.constructTCPSocketInstance();
tcp.connect({ address: {address: '192.168.xx.xxx', port: xxxx, family: 1} , timeout: 6000}, err => {
 if (err) {
   console.log('connect fail');
   return;
 }
 console.log('connect success');
})
  • 发送/接收数据
//发送数据  
send(options: TCPSendOptions, callback: AsyncCallback<void>): void
通过TCPSocket连接发送数据。使用callback方式作为异步方法。
说明: connect方法调用成功后,才可调用此方法。
需要权限:ohos.permission.INTERNET
系统能力:SystemCapability.Communication.NetStack
示例:
 tcpSend()
    {
        tcp.send({
            data: this.app_msg,
        }, err => {
            if (err) {
                console.log('send fail');
                return;
            }
        });
    },

//接收数据  并解析数据为String
on(type: ‘message’, callback: Callback<{message: ArrayBuffer, remoteInfo: SocketRemoteInfo}>): void
订阅TCPSocket连接的接收消息事件。使用callback方式作为异步方法。
系统能力:SystemCapability.Communication.NetStack
tcp.on('message', value => {
            console.log("on message")
            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("on connect received:" + str)
            this.receive_data=str;
            prompt.showToast({
                message:str,
                duration:1000
            });
 });

1.2 TPC send实现

按照上一节的流程,编写对应的JS程序即可。UI如下:
#DAYU200体验官# Dayu200与Hi3861 TCP通信(JS)-鸿蒙开发者社区
第一个按钮用于绑定IP,并设置订阅TCPSocket相关的订阅事件

 tcpClient()
    {
         // 订阅TCPSocket相关的订阅事件
        tcp.on('message', value => {
            console.log("on message")
            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("on connect received:" + str)
            this.receive_data=str;
            prompt.showToast({
                message:str,
                duration:1000
            });
        });
        tcp.on('connect', () => {
            console.log("on connect")
        });
        tcp.on('close', () => {
            console.log("on close")
        });

        // 绑定IP地址和端口。
        let bindAddress = {
            address: wifi.getIpInfo().ipAddress,
            port: 1234,
            family: 1
        };
        tcp.bind(bindAddress, err => {
            if (err) {
                console.log('bind fail');
                return;
            }
            console.log('bind success');
            prompt.showToast({
                message:"bind success",
            })
        });
    },

第二个按钮用于连接Hi3861:

 tcpConnect()
    {
        prompt.showToast({
            message:'wifiAddr'+wifi.isConnected()+wifi.getIpInfo().ipAddress,
        });
//        let promise = tcp.connect({ address: {address:'192.168.137.92', port: 8888, family: 1} , timeout: 6000});
//        promise.then(() => {
//            console.log('connect success')
//            prompt.showToast({
//                message:"connect success",
//            });
//        }).catch(err => {
//             prompt.showToast({
//                    message:"connect fail",
//                });
//            console.log('connect fail');
//        });
        tcp.connect({ address: {address: '192.168.137.92', port: 8888, family: 1} , timeout: 6000}, err => {
            if (err) {
                console.log('connect fail');
                 prompt.showToast({
                        message:"connect fail",
                    });
                return;
            }
            console.log('connect success');
            prompt.showToast({
                message:"connect success",
            });
        })
    },

第三个按钮实现发送数据:

tcpSend()
    {
        tcp.send({
            data: this.app_msg,
        }, err => {
            if (err) {
                console.log('send fail');
                prompt.showToast({
                    message:"send fail",
                });
                return;
            }
            prompt.showToast({
                message:"send successful"
            })
        });
    },

2. Hi3861 TCP

2.1 初始化

参考小熊派开发板TCP server案例。主要任务是开启wifi,获取周围wifi列表。

#define SELECT_WLAN_PORT "wlan0"
int WifiConnect(const char *ssid, const char *psk)
{
    WifiScanInfo *info = NULL;
    unsigned int size = WIFI_SCAN_HOTSPOT_LIMIT;
    static struct netif *g_lwip_netif = NULL;
    osDelay(200);
    printf("<--System Init-->\r\n");
    //初始化WIFI
    WiFiInit();
    //使能WIFI
    if (EnableWifi() != WIFI_SUCCESS)
    {
        printf("EnableWifi failed, error = %d\r\n", error);
        return -1;
    }
    //判断WIFI是否激活
    if (IsWifiActive() == 0)
    {
        printf("Wifi station is not actived.\r\n");
        return -1;
    }
    //分配空间,保存WiFi信息
    info = malloc(sizeof(WifiScanInfo) * WIFI_SCAN_HOTSPOT_LIMIT);
    if (info == NULL)
    {
        return -1;
    }
    //轮询查找WiFi列表
    do{
        //重置标志位
        ssid_count = 0;
        g_staScanSuccess = 0;
        //开始扫描
        Scan();
        //等待扫描结果
        WaitSacnResult();
        //获取扫描列表
        error = GetScanInfoList(info, &size);
    }while(g_staScanSuccess != 1);
    
    //连接指定的WiFi热点
    for(uint8_t i = 0; i < ssid_count; i++)
    {
        if (strcmp(ssid, info[i].ssid) == 0)
        {
            int result;

            printf("Select:%3d wireless, Waiting...\r\n", i+1);

            //拷贝要连接的热点信息
            WifiDeviceConfig select_ap_config = {0};
            strcpy(select_ap_config.ssid, info[i].ssid);
            strcpy(select_ap_config.preSharedKey, psk);
            select_ap_config.securityType = SELECT_WIFI_SECURITYTYPE;

            if (AddDeviceConfig(&select_ap_config, &result) == WIFI_SUCCESS)
            {
                if (ConnectTo(result) == WIFI_SUCCESS && WaitConnectResult() == 1)
                {
                    printf("WiFi connect succeed!\r\n");
                    g_lwip_netif = netifapi_netif_find(SELECT_WLAN_PORT);
                    break;
                }
            }
        }

        if(i == ssid_count-1)
        {
            printf("ERROR: No wifi as expected\r\n");
            while(1) osDelay(100);
        }
    }
     //启动DHCP
    if (g_lwip_netif)
    {
        dhcp_start(g_lwip_netif);
        printf("begain to dhcp\r\n");
    }
    //等待DHCP
    for(;;)
    {
        if(dhcp_is_bound(g_lwip_netif) == ERR_OK)
        {
            printf("<-- DHCP state:OK -->\r\n");
            //打印获取到的IP信息
            netifapi_netif_common(g_lwip_netif, dhcp_clients_info_show, NULL);
            break;
        }
        printf("<-- DHCP state:Inprogress -->\r\n");
        osDelay(100);
    }
    osDelay(100);
    return 0;
}

2.2 作为TCP Server

连接指定wifi,创建socket server,监听指定IP 端口。

char *buf = "Hello! I'm BearPi-HM_Nano TCP Server!";

static void TCPServerTask(void)
{
	//服务端地址信息
	struct sockaddr_in server_sock;

	//客户端地址信息
	struct sockaddr_in client_sock;
	int sin_size;

	struct sockaddr_in *cli_addr;

	//连接Wifi
	WifiConnect("r1", "88888889");

	//创建socket
	if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		perror("socket is error\r\n");
		exit(1);
	}

	bzero(&server_sock, sizeof(server_sock));
	server_sock.sin_family = AF_INET;
	server_sock.sin_addr.s_addr = htonl(INADDR_ANY);
	server_sock.sin_port = htons(_PROT_);

	//调用bind函数绑定socket和地址
	if (bind(sock_fd, (struct sockaddr *)&server_sock, sizeof(struct sockaddr)) == -1)
	{
		perror("bind is error\r\n");
		exit(1);
	}

	//调用listen函数监听(指定port监听)
	if (listen(sock_fd, TCP_BACKLOG) == -1)
	{
		perror("listen is error\r\n");
		exit(1);
	}

	printf("start accept\n");

	//调用accept函数从队列中
	while (1)
	{
		sin_size = sizeof(struct sockaddr_in);

		if ((new_fd = accept(sock_fd, (struct sockaddr *)&client_sock, (socklen_t *)&sin_size)) == -1)
		{
			perror("accept");
			continue;
		}

		cli_addr = malloc(sizeof(struct sockaddr));

		printf("accept addr\r\n");

		if (cli_addr != NULL)
		{
			memcpy(cli_addr, &client_sock, sizeof(struct sockaddr));
		}

		//处理目标
		ssize_t ret;

		while (1)
		{
			if ((ret = recv(new_fd, recvbuf, sizeof(recvbuf), 0)) == -1)
			{
				printf("recv error \r\n");
			}
			printf("recv :%s\r\n", recvbuf);
			sleep(2);
			if ((ret = send(new_fd, buf, strlen(buf) + 1, 0)) == -1)
			{
				perror("send : ");
			}

			sleep(2);
		}

		close(new_fd);
	}
}

3. 测试

将Hi3861、Dayu200都连接到同一个wifi下,事先匹配好IP地址和端口:
#DAYU200体验官# Dayu200与Hi3861 TCP通信(JS)-鸿蒙开发者社区
连接后Hi3861只要接收到数据就会返回一段字符串,Hi3861接收到的数据可以使用串口查看:
#DAYU200体验官# Dayu200与Hi3861 TCP通信(JS)-鸿蒙开发者社区

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2022-5-30 10:25:32修改
11
收藏 13
回复
举报
1条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

非常实用的演示,学习了

1
回复
2022-5-30 08:20:34
回复
    相关推荐