用socket API寫的wifi_test.c
阿新 • • 發佈:2021-01-17
技術標籤:STM32
#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); }