2020征文#使用Hi3861完成连接wifi热点并启动TCPSocketServer 精华

LegendOfTiger
发布于 2021-1-30 19:38
浏览
8收藏

这次使用Hi3861来完成Wifi热点的连接,并启动TCP SocketServer,接收消息并将消息反馈TcpCLient。

一、连接Wifi热点。主要做法是启动开发板Wifi,然后设置热点和密码等配置信息,再连接热点。

1、先定义两个Wifi监听器,一个连接改变、一个状态改变,并注册监听器。其中重要的是OnWifiConnectionChanged连接状态事件处理函数。该函数会在连接成功后设置全局变量g_connected=1,代表已经连接成功。

WifiEvent eventListener = {
  .OnWifiConnectionChanged = OnWifiConnectionChanged,
  .OnWifiScanStateChanged = OnWifiScanStateChanged
};
WifiErrorCode errCode = RegisterWifiEvent(&eventListener);

void OnWifiConnectionChanged(int state, WifiLinkedInfo* info) {
  if (!info) return;

  if (state == WIFI_STATE_AVALIABLE) {
    g_connected = 1;
  } else {
    g_connected = 0;
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

2、启动Wifi

EnableWifi();
  • 1.

3、设置Wifi热点信息,并返回NetworkId

WifiDeviceConfig apConfig = {};
strcpy(apConfig.ssid, "MyWifi");
strcpy(apConfig.preSharedKey, "12345678");
apConfig.securityType = WIFI_SEC_TYPE_PSK;

int netId = -1;
AddDeviceConfig(&apConfig, &netId);
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

4、连接热点,注意此时的g_connected变量,true代表已连接,false代表未连接。这个状态在事件处理函数中设置。未连接成功时,系统会循环等待,知道事件设置该值。

ConnectTo(netId);
while (!g_connected) {
  osDelay(10);
}
  • 1.
  • 2.
  • 3.
  • 4.

 

二、进行联网,找到wlan0的network interface,然后启动DHCP客户端,获取IP地址。

struct netif* iface = netifapi_netif_find("wlan0");
if (iface) {
  err_t ret = netifapi_dhcp_start(iface);
  osDelay(300);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

 

三、启动TcpSocketServer,并收发消息

1、创建SocketServer,设置服务端口,并启动监听

int sockfd = socket(AF_INET, SOCK_STREAM, 0);

struct sockaddr_in serverAddr = {0};
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(port);
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr));

int backlog = 1;
listen(sockfd, backlog)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

2、客户端连接。接收客户端消息并发送回去。注意连接后,会创建一个新的Socket File Description。

int connfd = -1;
connfd = accept(sockfd, (struct sockaddr *)&clientAddr, &clientAddrLen);

recv(connfd, request, sizeof(request), 0);
send(connfd, request, strlen(request), 0);
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

3、关闭TcpSocketServer

lwip_close(connfd);
lwip_close(socketfd);
  • 1.
  • 2.

 

四、联网结束,关闭DHCP客户端,断开Wifi,移除热点的配置信息,禁用Wifi。

err_t ret = netifapi_dhcp_stop(iface);
Disconnect();
RemoveDevice(netId);
DisableWifi();
  • 1.
  • 2.
  • 3.
  • 4.

 

五、测试情况如下:

1、启动开发板,连接Wifi热点,启动TcpServer

2020征文#使用Hi3861完成连接wifi热点并启动TCPSocketServer-鸿蒙开发者社区2、TcpClient(网络调试助手)连接开发板的TcpServer(HiBurn)。

2020征文#使用Hi3861完成连接wifi热点并启动TCPSocketServer-鸿蒙开发者社区2020征文#使用Hi3861完成连接wifi热点并启动TCPSocketServer-鸿蒙开发者社区3、TcpClient输入数据并发送,TcpServer接收后再发送回TcpClient。

2020征文#使用Hi3861完成连接wifi热点并启动TCPSocketServer-鸿蒙开发者社区2020征文#使用Hi3861完成连接wifi热点并启动TCPSocketServer-鸿蒙开发者社区

六、全部源代码,我都注释了,希望大家能够有所参考。

#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifi_device.h"

#include "lwip/netifapi.h"
#include "lwip/api_shell.h"
#include "lwip/sockets.h"

// 接收、发送的数据
static char request[128] = "";
// 未连接热点=0,已连接热点=1
static int g_connected = 0;

// 输出连接信息字符串
// 打印内容样例--> bssid: 38:47:BC:49:01:FA, rssi: 0, connState: 0, reason: 0, ssid: MyMobile
void PrintLinkedInfo(WifiLinkedInfo* info) {
  if (!info) return;

  static char macAddress[32] = {0};
  unsigned char* mac = info->bssid;
  snprintf(macAddress, sizeof(macAddress), "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  printf("bssid: %s, rssi: %d, connState: %d, reason: %d, ssid: %srn", macAddress, info->rssi, info->connState, info->disconnectedReason, info->ssid);
}

// 连接状态改变事件处理
void OnWifiConnectionChanged(int state, WifiLinkedInfo* info) {
  if (!info) return;

  // 输出类似内容:OnWifiConnectionChanged 31, state = 1, info = 
  printf("%s %d, state = %d, info = rn", __FUNCTION__, __LINE__, state);
  PrintLinkedInfo(info);

  // 根据连接状态设置g_connected
  if (state == WIFI_STATE_AVALIABLE) {
    g_connected = 1;
  } else {
    g_connected = 0;
  }
}

// 扫描状态改变事件处理
void OnWifiScanStateChanged(int state, int size) {
  printf("%s %d, state = %X, size = %drn", __FUNCTION__, __LINE__, state, size);
}

void DisconnectTcpSocket(int connfd) {
  sleep(1);
  printf("do_disconnect...rn");
  lwip_close(connfd);
  sleep(1); // for debug
}

void CloseTcpSocket(int socketfd) {
  printf("do_cleanup...rn");

  lwip_close(socketfd);
}

static void TcpServerHandler(void) {
  ssize_t retval = 0;
  unsigned short port = 9118;

  // 创建一个通信的Socket,并返回一个Socket文件描述符。第一个参数IpV4,第二个参数SOCK_STREAM类型,第三个指用到的协议
  int sockfd = socket(AF_INET, SOCK_STREAM, 0);

  // 客户端地址和地址长度
  struct sockaddr_in clientAddr = {0};
  socklen_t clientAddrLen = sizeof(clientAddr);

  // 服务端地址
  struct sockaddr_in serverAddr = {0};
  serverAddr.sin_family = AF_INET;
  // htons是将整型变量从主机字节顺序转变成网络字节顺序,就是整数在地址空间存储方式变为高位字节存放在内存的低地址处
  serverAddr.sin_port = htons(port);
  // 监听本机的所有IP地址,INADDR_ANY=0x0
  // 将主机数转换成无符号长整型的网络字节顺序
  serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);

  // 服务端绑定端口
  retval = bind(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
  if (retval < 0) {
    printf("bind failed, %ld!rn", retval);
    CloseTcpSocket(sockfd);
    return;
  }
  printf("bind to port %d success!rn", port);

  // 开始监听,backlog指Pending连接队列增长到的最大长度。队列满了,再有新连接请求到达,则客户端ECONNREFUSED错误。如果支持重传,则请求忽略。
  int backlog = 1;
  retval = listen(sockfd, backlog);
  if (retval < 0) {
    printf("listen failed!rn");
    CloseTcpSocket(sockfd);
    return;
  }
  printf("listen with %d backlog success!rn", backlog);

  int outerFlag = 1;
  while (outerFlag) {
    // 接受客户端连接,成功会返回一个表示连接的 socket。clientAddr参数将会携带客户端主机和端口信息;失败返回 -1
    // 从Pending连接队列中获取第一个连接,根据sockfd的socket协议、地址族等内容创建一个新的socket文件描述,并返回。
    // 此后的 收、发 都在 表示连接的 socket 上进行;之后 sockfd 依然可以继续接受其他客户端的连接,
    // UNIX系统上经典的并发模型是“每个连接一个进程”——创建子进程处理连接,父进程继续接受其他客户端的连接
    // 鸿蒙liteos-a内核之上,可以使用UNIX的“每个连接一个进程”的并发模型liteos-m内核之上,可以使用“每个连接一个线程”的并发模型
    int connfd = -1;
    connfd = accept(sockfd, (struct sockaddr *)&clientAddr, &clientAddrLen);
    if (connfd < 0) {
      printf("accept failed, %d, %drn", connfd, errno);
      CloseTcpSocket(sockfd);
      outerFlag = 0;
    }
    printf("accept success, connfd = %d !rn", connfd);
    // inet_ntoa:网络地址转换成“.”点隔的字符串格式。ntohs:16位数由网络字节顺序转换为主机字节顺序。
    printf("client addr info: host = %s, port = %drn", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));

    int innerFlag = 1;
    // 接收消息,然后发送回去
    while (innerFlag) {
      // 后续 收、发 都在 表示连接的 socket 上进行;
      // 在新的Socket文件描述上接收信息.
      retval = recv(connfd, request, sizeof(request), 0);
      if (retval < 0) {
        printf("recv request failed, %ld!rn", retval);
        innerFlag = 0;
      } else if (retval == 0) {
        // 对方主动断开连接
        printf("client disconnected!rn");
        innerFlag = 0;
      } else {
        printf("recv request{%s} from client done!rn", request);

        // 发送数据
        retval = send(connfd, request, strlen(request), 0);
        if (retval <= 0) {
          printf("send response failed, %ld!rn", retval);
          innerFlag = 0;
        }
        printf("send response{%s} to client done!rn", request);

        // 清空缓冲区
        memset(&request, 0, sizeof(request));
    }

    DisconnectTcpSocket(connfd);

    outerFlag = 0;
  }

  CloseTcpSocket(sockfd);
}

static void TcpServerTask(void *arg) {
  (void)arg;
  
  // 先定义两个Wifi监听器,一个连接改变、一个状态改变
  WifiEvent eventListener = {
    .OnWifiConnectionChanged = OnWifiConnectionChanged,
    .OnWifiScanStateChanged = OnWifiScanStateChanged
  };

  // 等待10个系统Ticks。每个ticks多少个us,计算方式= 1000 * 1000 / osKernelGetTickFreq()
  osDelay(10);

  // 注册监听器
  WifiErrorCode errCode = RegisterWifiEvent(&eventListener);
  printf("RegisterWifiEvent: %drn", errCode);

  // 设置Wifi热点信息
  WifiDeviceConfig apConfig = {};
  strcpy(apConfig.ssid, "MyMobile");
  strcpy(apConfig.preSharedKey, "12345678");
  apConfig.securityType = WIFI_SEC_TYPE_PSK;

  int netId = -1;

  // 启用Wifi
  errCode = EnableWifi();
  printf("EnableWifi: %drn", errCode);
  osDelay(10);

  // 设置Wifi热点配置信息,返回生成的网络Id-netId。
  errCode = AddDeviceConfig(&apConfig, &netId);
  printf("AddDeviceConfig: %drn", errCode);

  // 根据网络Id连接到Wifi热点
  g_connected = 0;
  errCode = ConnectTo(netId);
  printf("ConnectTo(%d): %drn", netId, errCode);
  // 未连接完成,则一直等待。g_connected状态会在事件中设置。
  while (!g_connected) {
    osDelay(10);
  }
  printf("g_connected: %drn", g_connected);
  osDelay(50);

  // 联网业务开始,找到netifname=wlan0的netif。
  struct netif* iface = netifapi_netif_find("wlan0");
  if (iface) {
    // 启动DHCP客户端,获取IP地址
    err_t ret = netifapi_dhcp_start(iface);
    printf("netifapi_dhcp_start: %drn", ret);
    // 等待DHCP服务器反馈给予地址
    osDelay(300);
    // 执行线程安全的网络方法,第二个参数是voidFunc,第三个参数是errFunc。如果没有errFunc,那么就执行voidFunc。
    // netifapi_dhcp_start/netifapi_dhcp_stop等都是调用的netifapi_netif_common方法。
    // dhcp_clients_info_show显示信息
    /*
    server :
      server_id : 192.168.43.1
      mask : 255.255.255.0, 1
      gw : 192.168.43.1
      T0 : 3600
      T1 : 1800
      T2 : 3150
    clients <1> :
      mac_idx mac             addr            state   lease   tries   rto     
      0       b4c9b9af69f8    192.168.43.56   10      0       1       2      
    */
    ret = netifapi_netif_common(iface, dhcp_clients_info_show, NULL);
    printf("netifapi_netif_common: %drn", ret);
  }

  TcpServerHandler();

  // 联网业务结束,断开DHCP
  err_t ret = netifapi_dhcp_stop(iface);
  printf("netifapi_dhcp_stop: %drn", ret);

  // 断开Wifi热点连接
  Disconnect();

  // 移除Wifi热点的配置
  RemoveDevice(netId);

  // 关闭Wifi
  errCode = DisableWifi();
  printf("DisableWifi: %drn", errCode);
  osDelay(200);
}

static void TcpServerEntry(void) {
  osThreadAttr_t attr;

  attr.name = "TcpServerTask";
  attr.attr_bits = 0U;
  attr.cb_mem = NULL;
  attr.cb_size = 0U;
  attr.stack_mem = NULL;
  attr.stack_size = 10240;
  attr.priority = osPriorityNormal;

  if (osThreadNew((osThreadFunc_t)TcpServerTask, NULL, &attr) == NULL) {
    printf("SunLaoTest-Fail Create");
  }
}

APP_FEATURE_INIT(TcpServerEntry);
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
  • 182.
  • 183.
  • 184.
  • 185.
  • 186.
  • 187.
  • 188.
  • 189.
  • 190.
  • 191.
  • 192.
  • 193.
  • 194.
  • 195.
  • 196.
  • 197.
  • 198.
  • 199.
  • 200.
  • 201.
  • 202.
  • 203.
  • 204.
  • 205.
  • 206.
  • 207.
  • 208.
  • 209.
  • 210.
  • 211.
  • 212.
  • 213.
  • 214.
  • 215.
  • 216.
  • 217.
  • 218.
  • 219.
  • 220.
  • 221.
  • 222.
  • 223.
  • 224.
  • 225.
  • 226.
  • 227.
  • 228.
  • 229.
  • 230.
  • 231.
  • 232.
  • 233.
  • 234.
  • 235.
  • 236.
  • 237.
  • 238.
  • 239.
  • 240.
  • 241.
  • 242.
  • 243.
  • 244.
  • 245.
  • 246.
  • 247.
  • 248.
  • 249.
  • 250.
  • 251.
  • 252.
  • 253.
  • 254.
  • 255.
  • 256.
  • 257.
  • 258.
  • 259.
  • 260.
  • 261.
  • 262.
  • 263.

已于2021-2-1 14:54:44修改
6
收藏 8
回复
举报
6
4
8
4条回复
按时间正序
/
按时间倒序
LegendOfTiger
LegendOfTiger

\r\n因为发布的时候,总是报错,我都改为rn了。

回复
2021-1-30 19:39:17
老船夫
老船夫

赞一波

回复
2021-1-30 19:40:45
LegendOfTiger
LegendOfTiger 回复了 老船夫
赞一波

真快啊

回复
2021-1-31 10:41:32
爱有引力
爱有引力

厉害牛牪犇

回复
2021-2-1 11:38:25
回复
    相关推荐