用socket API写的wifi_test.c

#include <FreeRTOS.h>
#include <lwip/netdb.h>
#include <lwip/sockets.h>
#include <task.h>
#include "common.h"

/*
** 此文件用到了errno这个变量, 默认情况下不是线程安全的
** 为了使errno变量变为线程安全, 在common.c中已通过重写Keil MDK的__aeabi_errno_addr函数
** 重新指定errno变量的存放位置, 与FreeRTOS系统的FreeRTOS_errno绑定
**
** 输出不以\0结尾的字符串的方法:
** char str[5] = {'H', 'e', 'l', 'l', 'o'};
** printf("str=%.5s\n", str);
** 或
** printf("str=%.*s\n", sizeof(str), str);
**
**
** 双引号字符串自动包含\0
** char *str = "Hello"; // 只读字符串
** char str[] = "Hello"; // 可读可写的字符串
** 可直接用%s输出
** printf("str=%s\n", str);
**
** 通常, 网络收到的数据p->payload是不含\0的
** 所以不能用%s输出, 应该使用%.*s输出
** printf("Data: %.*s\n", p->len, p->payload);
*/

/*** [DNS TEST] ***/
#if LWIP_DNS
static void dns_test_task(void *arg)
{
  char buffer[1024];
  char *name = "savannah.nongnu.org";
  char *request = "GET /news/?group=lwip HTTP/1.1\r\nHost: savannah.nongnu.org\r\n\r\n";
  int count = 0;
  int ipver = (int)arg;
  int ret;
  int retry = 6;
  int sockfd = -1;
  struct addrinfo hints = {0};
  struct addrinfo *result = NULL;
  
  switch (ipver)
  {
    case 4:
      hints.ai_family = AF_INET;
      break;
    case 6:
      hints.ai_family = AF_INET6;
      break;
    default:
      hints.ai_family = AF_UNSPEC;
      break;
  }
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_protocol = IPPROTO_TCP;
  hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV | AI_V4MAPPED;
retry:
  ret = getaddrinfo(name, "80", &hints, &result);
  if (ret == EAI_MEMORY)
  {
    printf_s("%s(%d): getaddrinfo() failed due to out of memory!\n", __FUNCTION__, ipver);
    if (retry == 0)
      goto end;
    else
    {
      printf_s("%s(%d): try again 10 seconds later.\n", __FUNCTION__, ipver);
      vTaskDelay(pdMS_TO_TICKS(10000));
      retry--;
      goto retry;
    }
  }
  else if (ret != 0 || result == NULL)
  {
    printf_s("%s(%d): getaddrinfo() failed! ret=%d, errno=%d\n", __FUNCTION__, ipver, ret, errno);
    goto end;
  }
  
  switch (result->ai_family)
  {
    case AF_INET:
      inet_ntop(AF_INET, &((struct sockaddr_in *)result->ai_addr)->sin_addr, buffer, sizeof(buffer));
      break;
    case AF_INET6:
      inet_ntop(AF_INET6, &((struct sockaddr_in6 *)result->ai_addr)->sin6_addr, buffer, sizeof(buffer));
      break;
    default:
      printf_s("%s(%d): invalid result->ai_family=%d\n", __FUNCTION__, ipver, result->ai_family);
      goto end;
  }
  printf_s("DNS Found IP of %s: %s\n", name, buffer);
  
  // 访问网页http://savannah.nongnu.org/news/?group=lwip
  // 注意: 现在绝大多数网站用的都是加密版本的https, 而下面的代码只能连接不加密的http网站
  // 所以下面的代码无法访问百度
  sockfd = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
  if (sockfd == -1)
  {
    printf_s("%s(%d): socket() failed! errno=%d\n", __FUNCTION__, ipver, errno);
    goto end;
  }
  
  printf_s("TCP socket is connecting to %s...\n", buffer);
  ret = connect(sockfd, result->ai_addr, result->ai_addrlen);
  if (ret == -1)
  {
    printf_s("TCP socket connection failed! errno=%d\n", errno);
    goto end;
  }
  
  printf_s("TCP socket is connected!\n");
  send(sockfd, request, strlen(request), 0); // 发送HTTP请求头
  while (1)
  {
    ret = recv(sockfd, buffer, sizeof(buffer), 0);
    if (ret > 0)
    {
      printf_s("%s(%d): %d bytes received!\n", __FUNCTION__, ipver, ret);
      count += ret;
    }
    else if (ret == 0)
    {
      printf_s("TCP socket is closed! count=%d\n", count);
      break;
    }
    else
    {
      printf_s("TCP socket error! ret=%d, errno=%d\n", ret, errno);
      break;
    }
  }
  
end:
  if (result != NULL)
    freeaddrinfo(result);
  if (sockfd != -1)
    close(sockfd);
  vTaskDelete(NULL);
}

void dns_test(int ipver)
{
  BaseType_t ret;
  
  ret = xTaskCreate(dns_test_task, "dns_test", 768, (void *)ipver, tskIDLE_PRIORITY, NULL);
  if (ret != pdPASS)
    printf_s("%s: failed to create a task! ret=%d\n", __FUNCTION__, ret);
}
#endif

/*** [TCP SPEED TEST] ***/
static uint8_t tcp_tester_buffer[15000];

static void tcp_tester_client_task(void *arg)
{
  char ip[INET6_ADDRSTRLEN];
  char rcvbuf[10];
  fd_set readset, writeset;
  int clientfd = (int)arg;
  int port, ret;
  socklen_t addrlen;
  struct sockaddr_in6 addr;
  struct timeval tv = {0};
  
  addrlen = sizeof(addr);
  ret = getpeername(clientfd, (struct sockaddr *)&addr, &addrlen);
  if (ret == -1)
  {
    printf_s("%s: getpeername() failed! errno=%d\n", __FUNCTION__, errno);
    goto err;
  }
  inet_ntop(AF_INET6, &addr.sin6_addr, ip, sizeof(ip));
  port = ntohs(addr.sin6_port);
  printf_s("TCP tester accepted [%s]:%d!\n", ip, port);
  
  FD_ZERO(&readset);
  FD_ZERO(&writeset);
  while (1)
  {
    FD_SET(clientfd, &readset);
    FD_SET(clientfd, &writeset);
    ret = select(clientfd + 1, &readset, &writeset, NULL, &tv);
    if (ret == -1)
    {
      printf_s("%s: select() failed! errno=%d\n", __FUNCTION__, errno);
      break;
    }
    else if (FD_ISSET(clientfd, &readset))
    {
      // 有数据可接收
      ret = recv(clientfd, rcvbuf, sizeof(rcvbuf), 0);
      printf_s("TCP tester received %d bytes from [%s]:%d!\n", ret, ip, port);
      printf_s("TCP tester stopped sending data!\n");
      break;
    }
    else if (FD_ISSET(clientfd, &writeset))
    {
      // 发送数据
      ret = send(clientfd, tcp_tester_buffer, sizeof(tcp_tester_buffer), 0);
      if (ret == -1)
      {
        printf_s("%s: send() failed! errno=%d\n", __FUNCTION__, errno);
        break;
      }
    }
  }
  
  printf_s("TCP tester client [%s]:%d closed!\n", ip, port);
err:
  close(clientfd);
  vTaskDelete(NULL);
}

static void tcp_tester_task(void *arg)
{
  int clientfd, serverfd = -1;
  int ret;
  socklen_t addrlen;
  struct sockaddr_in6 addr = {0};
  
  serverfd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
  if (serverfd == -1)
  {
    printf_s("%s: socket() failed! errno=%d\n", __FUNCTION__, errno);
    goto err;
  }
  
  addr.sin6_family = AF_INET6;
  addr.sin6_port = htons(24001);
  ret = bind(serverfd, (struct sockaddr *)&addr, sizeof(addr));
  if (ret == -1)
  {
    printf_s("%s: bind() failed! errno=%d\n", __FUNCTION__, errno);
    goto err;
  }
  
  ret = listen(serverfd, 5);
  if (ret == -1)
  {
    printf_s("%s: listen() failed! errno=%d\n", __FUNCTION__, errno);
    goto err;
  }
  
  while (1)
  {
    addrlen = sizeof(addr);
    clientfd = accept(serverfd, (struct sockaddr *)&addr, &addrlen);
    if (clientfd != -1)
    {
      ret = xTaskCreate(tcp_tester_client_task, "tcp_tester_client", 384, (void *)clientfd, tskIDLE_PRIORITY, NULL);
      if (ret != pdPASS)
      {
        printf_s("%s: could not accept a new client!\n", __FUNCTION__);
        close(clientfd);
      }
    }
    else
      printf_s("%s: accept() failed! errno=%d\n", __FUNCTION__, errno);
  }
  
err:
  if (serverfd != -1)
    close(serverfd);
  vTaskDelete(NULL);
}

void tcp_tester_init(void)
{
  BaseType_t ret;
  
  ret = xTaskCreate(tcp_tester_task, "tcp_tester", 256, NULL, tskIDLE_PRIORITY, NULL);
  if (ret != pdPASS)
    printf_s("%s: failed to create a task! ret=%d\n", __FUNCTION__, ret);
}

/*** [UDP TEST] ***/
struct test
{
  uint32_t id;
  uint32_t count;
};

static void udp_tester_task(void *arg)
{
  char ip[INET6_ADDRSTRLEN];
  int ret;
  int serverfd = -1;
  socklen_t addrlen;
  struct sockaddr_in6 addr = {0};
  struct test *t = (struct test *)tcp_tester_buffer;
  
  serverfd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
  if (serverfd == -1)
  {
    printf_s("%s: socket() failed! errno=%d\n", __FUNCTION__, errno);
    goto err;
  }
  
  addr.sin6_family = AF_INET6;
  addr.sin6_port = htons(24002);
  ret = bind(serverfd, (struct sockaddr *)&addr, sizeof(addr));
  if (ret == -1)
  {
    printf_s("%s: bind() failed! errno=%d\n", __FUNCTION__, errno);
    goto err;
  }
  
  LWIP_ASSERT("sizeof(struct test) <= sizeof(tcp_tester_buffer)", sizeof(struct test) <= sizeof(tcp_tester_buffer));
  while (1)
  {
    addrlen = sizeof(addr);
    ret = recvfrom(serverfd, tcp_tester_buffer, sizeof(tcp_tester_buffer), 0, (struct sockaddr *)&addr, &addrlen);
    if (ret != -1)
    {
      // 每从客户端收到一个数据包, 都发送一批数据包作为回应
      inet_ntop(AF_INET6, &addr.sin6_addr, ip, sizeof(ip));
      printf_s("Sending UDP packets to [%s]:%d...\n", ip, ntohs(addr.sin6_port));
      t->count = 1024;
      for (t->id = 0; t->id < t->count; t->id++)
      {
        ret = sendto(serverfd, tcp_tester_buffer, 1300, 0, (struct sockaddr *)&addr, sizeof(addr));
        if (ret == -1)
        {
          printf_s("%s: sendto() failed! errno=%d, t->id=%d\n", __FUNCTION__, errno, t->id);
          break;
        }
      }
    }
    else
      printf_s("%s: recvfrom() failed! errno=%d\n", __FUNCTION__, errno);
  }
  
err:
  if (serverfd != -1)
    close(serverfd);
  vTaskDelete(NULL);
}

void udp_tester_init(void)
{
  BaseType_t ret;
  
  ret = xTaskCreate(udp_tester_task, "udp_tester", 384, NULL, tskIDLE_PRIORITY, NULL);
  if (ret != pdPASS)
    printf_s("%s: failed to create a task! ret=%d\n", __FUNCTION__, ret);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

巨大八爪鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值