一、簡介
? ? ? ? 在網(wǎng)絡(luò)編程的時候,不管是客戶端還是服務(wù)端,都離不開Socket。那什么是Socket,這里做個簡單介紹。詳細(xì)的內(nèi)容,可以參考這篇文章:WIFI學(xué)習(xí)一(socket介紹)_wifi socket_t_guest的博客-CSDN博客
?????????socket在計算機(jī)領(lǐng)域,被翻譯為“套接字”。它是計算機(jī)之間進(jìn)行通信的一種約定或一種方式,通過這種方式,一臺計算機(jī)可以接收或向另外一臺計算機(jī)收發(fā)數(shù)據(jù)。
? ? ? ? socket是基于“打開open –> 讀寫write/read –> 關(guān)閉close”模式來設(shè)計的。socket可以看做是一種特殊的文件,通過一下socket函數(shù)來實(shí)現(xiàn)打開、關(guān)閉和讀/寫IO。
? ? ? ? socket客戶端編程的總體流程可以歸結(jié)為以下步驟,初始化socket,連接服務(wù)器(connect),讀/寫(write/read),關(guān)閉(close)。
?二、API介紹
??????socket
????????函數(shù)功能:
? ? ? ? 創(chuàng)建一個socket描述符,用來唯一標(biāo)識一個socket。后續(xù)需要通過該描述符進(jìn)行讀寫操作。
? ? ? ? 函數(shù)原型:
int socket(int domain, int type, int protocol)
????????參數(shù):
? ? ? ? domain:IP地址類型。常用的類型有AF_INET(IPV4)、AF_INET6(IPV6)。
? ? ? ? type:數(shù)據(jù)傳輸方式/套接字類型。常用的類型有SOCK_STREAM(流格式套接字/面向連接的套接字?TCP)、SOCK_DGRAM(數(shù)據(jù)報套接字/無連接的套接字?UDP)。
? ? ? ? protocol:傳輸協(xié)議。?默認(rèn)為0,系統(tǒng)自動推演使用的協(xié)議。也可以手動輸入,常用的協(xié)議有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它們分別對應(yīng)TCP傳輸協(xié)議、UDP傳輸協(xié)議、STCP傳輸協(xié)議、TIPC傳輸協(xié)議。type和protocol不可以隨意組合,如SOCK_STREAM不可以跟IPPROTO_UDP組合。
? ? ? ? 返回值:
? ? ? ? NULL:失敗
? ? ? ? 其他值:Sockcet描述符
? ? ? ? 實(shí)例:
int tcp_socket = socket(AF_INET, SOCK_STREAM, 0); //創(chuàng)建TCP套接字
int udp_socket = socket(AF_INET, SOCK_DGRAM, 0); //創(chuàng)建UDP套接字
??????lwip_connect
????????函數(shù)功能:
? ? ? ? 客戶端通過該函數(shù)與服務(wù)端建立連接
? ? ? ? 函數(shù)原型:
#define lwip_connect connect
int connect(int fd, const struct sockaddr *addr, socklen_t len)
????????參數(shù):
? ? ? ? fd:socket描述符,socket()函數(shù)返回。
????????addr:要連接的服務(wù)端相關(guān)信息,包括IP和端口等
????????len:服務(wù)端相關(guān)信息的長度
? ? ? ? 返回值:
? ? ? ? -1:失敗
? ? ? ? 0:成功
? ? ? ? 實(shí)例:
int sock_fd;
struct sockaddr_in socket_addr;
memset(&socket_addr, 0, sizeof(socket_addr));
socket_addr.sin_family = AF_INET; //IPV4
socket_addr.sin_port = htons(_PROT_); //端口
socket_addr.sin_addr.s_addr = inet_addr("192.168.3.198"); //IP地址轉(zhuǎn)換
socklen_t addr_length = sizeof(socket_addr);
LOG_I( "connect port:%d, addr:%s",_PROT_,inet_ntoa(socket_addr.sin_addr));
int ret = 0;
ret = lwip_connect(sock_fd, (struct sockaddr *)&socket_addr, addr_length);
if(ret < 0) //失敗{}
? ? ? ? ?如果網(wǎng)關(guān)即為服務(wù)端,這里相關(guān)信息可以這么寫。
struct netif *sta_if = netifapi_netif_find("wlan0");
socket_addr.sin_addr.s_addr = inet_addr(ipaddr_ntoa(&sta_if->gw)); //網(wǎng)關(guān)IP
??????lwip_write
????????函數(shù)功能:
? ? ? ? 向套接字寫數(shù)據(jù)
? ? ? ? 函數(shù)原型:
ssize_t lwip_write(int s, const void *data, size_t size)
????????參數(shù):
? ? ? ? s:socket描述符,socket()函數(shù)返回。
? ? ? ? data:要發(fā)送的數(shù)據(jù)
? ? ? ? size:要發(fā)送數(shù)據(jù)的長度
? ? ? ? 返回值:
? ? ? ? -1:失敗
? ? ? ? 其他值:成功發(fā)送的字節(jié)數(shù)
? ? ? ? 實(shí)例:
int sock_fd;
const char *send_data = "This is a socket client test!\r\n";
if(lwip_write(sock_fd,send_data, strlen(send_data)) != -1) //發(fā)送成功
{}
??????lwip_read
????????函數(shù)功能:
? ? ? ? 從套接字中讀取數(shù)據(jù)。阻塞等待
? ? ? ? 函數(shù)原型:
ssize_t lwip_read(int s, void *mem, size_t len)
????????參數(shù):
????????s:socket描述符,socket()函數(shù)返回。
? ? ? ? mem:接收到的數(shù)據(jù)存儲的地址
? ? ? ? len:最大接收數(shù)據(jù)長度
? ? ? ? 返回值:
????????-1:失敗
????????其他值:成功則返回讀取到的字節(jié)數(shù),遇到文件結(jié)尾則返回0
? ? ? ? 實(shí)例:
int sock_fd;
char recvBuf[512] = {0};
if((temp_len = lwip_read(sock_fd, recvBuf, sizeof(recvBuf))) > 0) //讀成功
{}
??????lwip_close
????????函數(shù)功能:
? ? ? ? 關(guān)閉之前打開的套接字
? ? ? ? 函數(shù)原型:
int closesocket(int s)
????????參數(shù):
????????s:socket描述符,socket()函數(shù)返回。
? ? ? ? 返回值:
? ? ? ? 0:成功
? ? ? ? 其他值:失敗
? ? ? ? 實(shí)例:
int sock_fd;
closesocket(sock_fd);
??????sendto
????????函數(shù)功能:
? ? ? ? 發(fā)送數(shù)據(jù)到服務(wù)器端(一般用于UDP)。
? ? ? ? 函數(shù)原型:
ssize_t sendto(int fd, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t alen)
????????參數(shù):
? ? ? ? fd:socket描述符,socket()的返回值。
? ? ? ? buf:要發(fā)送的數(shù)據(jù)
? ? ? ? len:要發(fā)送數(shù)據(jù)的長度
? ? ? ? flags:默認(rèn)0
? ? ? ? addr:服務(wù)端相關(guān)信息。
? ? ? ? alen:服務(wù)端信息長度
? ? ? ? 返回值:
? ? ? ? -1:失敗
? ? ? ? 其他值:成功發(fā)送的字節(jié)數(shù)
? ? ? ? 實(shí)例:
int sock_fd;
//服務(wù)器的地址信息
struct sockaddr_in send_addr;
socklen_t addr_length = sizeof(send_addr);
//初始化預(yù)連接的服務(wù)端地址
send_addr.sin_family = AF_INET;
send_addr.sin_port = htons(_PROT_);
send_addr.sin_addr.s_addr = inet_addr("192.168.3.198");
addr_length = sizeof(send_addr);
sendto(sock_fd, send_data, strlen(send_data), 0, (struct sockaddr *)&send_addr, addr_length);
??????recvfrom
????????函數(shù)功能:
? ? ? ? 接收socket傳輸過來的數(shù)據(jù)(一般用于UDP),阻塞等待。
? ? ? ? 函數(shù)原型:
ssize_t recvfrom(int s, void *mem, size_t len, int flags,
struct sockaddr *from, socklen_t *fromlen)
????????參數(shù):
????????s:socket描述符,socket()函數(shù)返回。
? ? ? ? mem:接收到的數(shù)據(jù)存放的地址
? ? ? ? len:最大接收數(shù)據(jù)長度、
? ? ? ? flags:默認(rèn)為0。
? ? ? ? addr:服務(wù)端相關(guān)信息。
? ? ? ? alen:服務(wù)端信息長度
? ? ? ? 返回值:
? ? ? ? -1:失敗
? ? ? ? 其他值:接收到的數(shù)據(jù)長度
? ? ? ? 實(shí)例:
int sock_fd; //在sock_fd 進(jìn)行監(jiān)聽,在 new_fd 接收新的鏈接
char recvBuf[512] = {0};
//服務(wù)器的地址信息
struct sockaddr_in send_addr;
socklen_t addr_length = sizeof(send_addr);
//初始化預(yù)連接的服務(wù)端地址
send_addr.sin_family = AF_INET;
send_addr.sin_port = htons(_PROT_);
send_addr.sin_addr.s_addr = inet_addr("192.168.3.198");
addr_length = sizeof(send_addr);
recvfrom(sock_fd, recvBuf, sizeof(recvBuf), 0, (struct sockaddr *)&send_addr, &addr_length);
??????lwip_setsockopt
????????函數(shù)功能:
? ? ? ? 設(shè)置套接字描述符選項(xiàng)
? ? ? ? 函數(shù)原型:
#define lwip_setsockopt setsockopt
int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
????????參數(shù):
????????s:socket描述符,socket()函數(shù)返回。
? ? ? ? level:選項(xiàng)定義的層次
SOL_SOCKET,套接字層
IPPROTO_TCP,TCP層
IPPROTO_IP,IP層
IPPROTO_IPV6,IPV6層
? ? ? ? optname:需要設(shè)置的選項(xiàng)。這里只介紹常用的選項(xiàng)。在level為SOL_COCKET(套接字層)時,optname可選一下值:
/*設(shè)置發(fā)送超時*/
#define SO_SNDTIMEO 0x1005 /* send timeout */
/*設(shè)置接收超時*/
#define SO_RCVTIMEO 0x1006 /* receive timeout */
? ? ? ? ?optval:指向存放選項(xiàng)待設(shè)置新值的緩沖區(qū)
? ? ? ? optlen:緩沖區(qū)長度
? ? ? ? 返回值:
? ? ? ? -1:失敗
? ? ? ? 0:成功
? ? ? ? 實(shí)例:
struct timeval timeout;
timeout.tv_sec = 30; //秒
timeout.tv_usec = 0; //微秒
if (setsockopt(client, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0) {
LOG_I(lwip_socket_example, "Setsockopt failed - set rcvtimeo\n");
}
??????htonl()、htons()、ntohl()、ntohs()
????????函數(shù)功能:
? ? ? ? 在編程的時候,往往會遇到網(wǎng)絡(luò)字節(jié)順序和主機(jī)順序的問題。這時就需要以上四個函數(shù)進(jìn)行調(diào)節(jié)了。
htonl()--"Host to Network Long"
ntohl()--"Network to Host Long"
htons()--"Host to Network Short"
ntohs()--"Network to Host Short"
? ? ? ? 主機(jī)順序:大端或小端。大端就是高位字節(jié)排放在內(nèi)存的低地址端,低位字節(jié)排放在內(nèi)存的高地址端(高位在前,低位在后)。小端就是低位字節(jié)排放在內(nèi)存的低地址端,高位字節(jié)排放在內(nèi)存的高地址端(低位在前,高位在后)。
? ? ? ? 網(wǎng)絡(luò)字節(jié)序:4個字節(jié)的32 bit值以下面的次序傳輸:首先是0~7bit,其次8~15bit,然后16~23bit,最后是24~31bit。這種傳輸次序稱作大端字節(jié)序。由于TCP/IP首部中所有的二進(jìn)制整數(shù)在網(wǎng)絡(luò)中傳輸時都要求以這種次序,因此它又稱作網(wǎng)絡(luò)字節(jié)序。
? ? ? ? 函數(shù)原型:
uint32_t htonl(uint32_t hostlong);
? ? ? ? 參數(shù):
? ? ? ? 轉(zhuǎn)換前的值
? ? ? ? 返回值:
? ? ? ? 轉(zhuǎn)換后的值
? ? ? ? 實(shí)例:
server_sock.sin_addr.s_addr = htonl(INADDR_ANY); //地址,隨意分配
????????
? ? ?inet_addr()??????
????????函數(shù)功能:???
? ? ? ? 轉(zhuǎn)換網(wǎng)絡(luò)主機(jī)地址(192.168.x.x)為網(wǎng)絡(luò)字節(jié)序排序地址。
? ? ? ? 函數(shù)原型:
in_addr_t inet_addr(const char* cp)
? ? ? ? 參數(shù):
? ? ? ? cp:網(wǎng)絡(luò)主機(jī)地址(192.168.x.x)
? ? ? ? 返回值:
? ? ? ? -1:失敗。當(dāng)cp無效時(255.255.255.0或其他)返回-1.
? ? ? ? 其他值:網(wǎng)絡(luò)字節(jié)排序地址
? ? ? ? 實(shí)例:
send_addr.sin_addr.s_addr = inet_addr("192.168.3.198");
? ? ?inet_aton()??????
????????函數(shù)功能:???
? ? ? ? 將主機(jī)地址(192.168.x.x)轉(zhuǎn)化為二進(jìn)制數(shù)值。
? ? ? ? 注:這個函數(shù)轉(zhuǎn)換完后不能用于網(wǎng)絡(luò)傳輸,還需要調(diào)用htons或htonl函數(shù)才能將主機(jī)字節(jié)順序轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)順序。
? ? ? ? 函數(shù)原型:
int inet_aton(const char* cp, struct in_addr* inp)
? ? ? ? 參數(shù):
? ? ? ? cp:輸入值,網(wǎng)絡(luò)主機(jī)地址(192.168.x.x)
? ? ? ? inp:輸出值,轉(zhuǎn)換后的二進(jìn)制數(shù)值
? ? ? ? 返回值:
? ? ? ? 0:主機(jī)地址無效
? ? ? ? 其他值:主機(jī)地址有效
? ? ? ? 實(shí)例:
struct sockaddr_in sin1;
inet_aton("127.0.0.1", &sin1.sin_addr);
? ? ?inet_ntoa()??????
????????函數(shù)功能:???
? ? ? ? 將網(wǎng)絡(luò)字節(jié)排序的地址轉(zhuǎn)換為ASICC(x.x.x.x)。
????????注:該字符串的空間為靜態(tài)分配,這意味著在第二次調(diào)用該函數(shù)時,上一次調(diào)用的輸出值將會被覆蓋。
? ? ? ? 函數(shù)原型:
char *inet_ntoa(struct in_addr in)
? ? ? ? 參數(shù):
? ? ? ? in:類型為in_addr。網(wǎng)絡(luò)字節(jié)排序地址。
typedef uint32_t in_addr_t;
? ? ? ? 返回值:
? ? ? ? 轉(zhuǎn)化的字符串
? ? ? ? 實(shí)例:
struct in_addr addr1,addr2;
addr1 = inet_addr("192.168.0.74");
addr2 = inet_addr("211.100.21.179");
printf("%s : %s\n", inet_ntoa(addr1), inet_ntoa(addr2)); //不可以這么用,結(jié)果會被覆蓋
printf("%s\n", inet_ntoa(addr1));
printf("%s\n", inet_ntoa(addr2));
輸出結(jié)果:
192.168.0.74 : 192.168.0.74 //從這里可以看出,printf里的inet_ntoa只運(yùn)行了一次。
192.168.0.74
211.100.21.179
? ? ?ipaddr_ntoa()??????
????????函數(shù)功能:???
????????將網(wǎng)絡(luò)地址類型的地址轉(zhuǎn)換為ASICC(x.x.x.x)。
? ? ? ? 注:ipaddr_ntoa和inet_ntoa的功能相同,都是將傳參轉(zhuǎn)換為字符串。但是傳參的數(shù)據(jù)類型不同,ipaddr_ntoa參數(shù)的類型為ip_addr_t的指針,而inet_ntoa參數(shù)為uint32_t類型的整型。
????????函數(shù)原型:
char *ipaddr_ntoa(const ip_addr_t *addr)
????????參數(shù):
? ? ? ? addr:網(wǎng)絡(luò)地址
????????返回值:
? ? ? ? 轉(zhuǎn)化的字符串
? ? ? ? 實(shí)例:
lwip_netif = netifapi_netif_find("ap0"); //獲取網(wǎng)絡(luò)借口,用于IP操作
LOG_I("ip addr:%s",ipaddr_ntoa(&lwip_netif->ip_addr));
? ? ?ipaddr_aton()??????
????????函數(shù)功能:???
? ? ? ? 將主機(jī)地址(192.168.1.1)轉(zhuǎn)化為網(wǎng)絡(luò)字節(jié)類型
????????函數(shù)原型:
int ipaddr_aton(const char *cp, ip_addr_t *addr)
????????參數(shù):
????????cp:輸入值,網(wǎng)絡(luò)主機(jī)地址(192.168.x.x)
? ? ? ? addr:輸出值,網(wǎng)絡(luò)地址,類型為ip_addr_t.
typedef struct ip_addr {
union {
ip6_addr_t ip6;
ip4_addr_t ip4;
} u_addr;
/** @ref lwip_ip_addr_type */
u8_t type;
} ip_addr_t;
? ? ? ? 返回值:
? ? ? ? 0:成功
? ? ? ? 其他值:失敗
? ? ? ? 實(shí)例:
struct netif *lwip_netif = NULL;
ipaddr_ntoa("192.168.1.1",&lwip_netif->ip_addr));
? ? ?inet_pton()??????
????????函數(shù)功能:???
? ? ? ? 將點(diǎn)分十進(jìn)制的IP地址(192.168.x.x)轉(zhuǎn)化為用于網(wǎng)絡(luò)傳輸?shù)臄?shù)據(jù)格式
? ? ? ? 函數(shù)原型:
int inet_pton(int af, const char *src, void *dst)
? ? ? ? 參數(shù):
? ? ? ? af:地址族,AF_INET(IPV4)、AF_INET6(IPV6)。
? ? ? ? src:輸入值,點(diǎn)分十進(jìn)制的IP地址(192.168.x.x)
? ? ? ? dst:輸出值,用于網(wǎng)絡(luò)傳輸?shù)臄?shù)據(jù)格式
? ? ? ? 返回值:
? ? ? ? -1:異常
? ? ? ? 0:輸入值異常
? ? ? ? 1:成功
? ? ? ? 實(shí)例:
struct sockaddr_in socket_addr;
inet_pton(AF_INET, "192.168.1.110", &socket_addr.sin_addr);
/*
代替socket_addr.sin_addr.s_addr = inet_addr("192.168.1.110"); //IP地址轉(zhuǎn)換
*/
? ? ?inet_ntop()??????
????????函數(shù)功能:???
? ? ? ? 將用于網(wǎng)絡(luò)傳輸?shù)臄?shù)據(jù)格式轉(zhuǎn)化為點(diǎn)分十進(jìn)制的IP地址格式(192.168.x.x)
? ? ? ? 函數(shù)原型:
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size)
? ? ? ? 參數(shù):
? ? ? ? af:地址族,AF_INET(IPV4)、AF_INET6(IPV6)。
? ? ? ? src:輸入值,網(wǎng)絡(luò)傳輸數(shù)據(jù)格式的數(shù)據(jù)
? ? ? ? dst:輸出值,IP地址格式(192.168.x.x)
? ? ? ? size:輸入值,目標(biāo)存儲單元大小。
? ? ? ? 返回值:
? ? ? ? 0:成功
? ? ? ? 其他值:失敗。ENOSPC size長度太小。
? ? ? ? 實(shí)例:
char str[INET_ADDRSTRLEN];
struct sockaddr_in socket_addr;
char *ptr = inet_ntop(AF_INET,&socket_addr.sin_addr, str, sizeof(str));
// 代替 ptr = inet_ntoa(socket_addr.sin_addr)
三、實(shí)例
? ? ? ? 這里分別創(chuàng)建一個TCP和一個UDP
? ? ? ? ?現(xiàn)在BUILD.gn文件中添加如下代碼
include_dirs = [
"http://utild/native/lite/include",
"http://base/iot_hardware/interfaces/kits/wifiiot_lite",
"http://utils/native/lite/include",
"http://kernel/liteos_m/components/cmsis/2.0",
"http://foundation/communication/interfaces/kits/wifi_lite/wifiservice",
"http://vendor/hisi/hi3861/hi3861/third_party/lwip_sack/include/",
]
/*TCP*/
#include <stdio.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 <netdb.h>
#include <string.h>
#include <stdlib.h>
#include "lwip/sockets.h"
#define LOG_I(fmt, args...) printf("<%8ld> - [SOCKET_CLIENT]:"fmt"\r\n",osKernelGetTickCount(),##args);
#define LOG_E(fmt, args...) printf("<%8ld>-[SOCKET_CLIENT_ERR]>>>>>>>>>>>>:"fmt"\r\n",osKernelGetTickCount(), ##args);
#define _PROT_ 7682
static const char *send_data = "Hello! I'm BearPi-HM_Nano UDP Client!\r\n";
static void SocketClientTask(void)
{
int sock_fd; //在sock_fd 進(jìn)行監(jiān)聽,在 new_fd 接收新的鏈接
char recvBuf[512] = {0};
//連接Wifi
extern int drv_wifi_connect(const char *ssid, const char *psk);
drv_wifi_connect("Harmony_test_ap", "123123123");
LOG_I("wifi connect success");
//創(chuàng)建socket
if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
LOG_E("create socket failed!\r\n");
exit(1);
}
LOG_I("socket TCP create done");
struct sockaddr_in socket_addr;
memset(&socket_addr, 0, sizeof(socket_addr));
socket_addr.sin_family = AF_INET; //IPV4
socket_addr.sin_port = htons(_PROT_); //端口
socket_addr.sin_addr.s_addr = inet_addr("192.168.3.198"); //IP地址轉(zhuǎn)換
// socket_addr.sin_addr.s_addr = inet_addr(ipaddr_ntoa(&sta_if->gw)); //網(wǎng)關(guān)IP
socklen_t addr_length = sizeof(socket_addr);
LOG_I( "connect port:%d, addr:%s",_PROT_,inet_ntoa(socket_addr.sin_addr));
int ret = 0;
do{
ret = lwip_connect(sock_fd, (struct sockaddr *)&socket_addr, addr_length);
if(ret != 0) //失敗
{
LOG_I("socket connect fail");
// lwip_close(sock_fd); //關(guān)閉socket
osDelay(100);
}
}while(ret != 0);
LOG_I("socket connect success");
struct timeval timeout;
timeout.tv_sec = 5; //秒
timeout.tv_usec = 0; //微秒
if (lwip_setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0) //設(shè)置接收超時
{
LOG_E("Setsockopt failed - set rcvtimeo\n");
}
LOG_I("set socket receive timeout:%d",timeout.tv_sec);
int temp_len = 0;
while(1)
{
bzero(recvBuf, sizeof(recvBuf));
if(lwip_write(sock_fd,send_data, strlen(send_data)) != -1)
{
LOG_I("socket write success");
}
else
{
LOG_E("socket write fail");
}
temp_len = 0;
if((temp_len = lwip_read(sock_fd, recvBuf, sizeof(recvBuf))) > 0) //讀成功
{
LOG_I( "TCP client >>>>>read>>>>> data,len:%d,data:%s", temp_len, recvBuf);
}
else
{
LOG_E("socket client read fail");
}
}
//關(guān)閉這個 socket
closesocket(sock_fd);
}
void app_socket_client_init(void)
{
osThreadAttr_t attr;
attr.name = "UDPClientTask";
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)SocketClientTask, NULL, &attr) == NULL)
{
LOG_E("[UDPClientDemo] Falied to create UDPClientTask!\n");
}
}
/*UDP*/
#include <stdio.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 <netdb.h>
#include <string.h>
#include <stdlib.h>
#include "lwip/sockets.h"
#define LOG_I(fmt, args...) printf("<%8ld> - [SOCKET_CLIENT]:"fmt"\r\n",osKernelGetTickCount(),##args);
#define LOG_E(fmt, args...) printf("<%8ld>-[SOCKET_CLIENT_ERR]>>>>>>>>>>>>:"fmt"\r\n",osKernelGetTickCount(), ##args);
#define _PROT_ 7682
static const char *send_data = "This is a UDP client test!\r\n";
static void SocketClientTask(void)
{
int sock_fd; //在sock_fd 進(jìn)行監(jiān)聽,在 new_fd 接收新的鏈接
char recvBuf[512] = {0};
//連接Wifi
extern int drv_wifi_connect(const char *ssid, const char *psk);
drv_wifi_connect("Harmony_test_ap", "123123123");
LOG_I("wifi connect success");
//創(chuàng)建socket
if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
LOG_E("create socket failed!\r\n");
exit(1);
}
LOG_I("socket UDP create done");
//服務(wù)器的地址信息
struct sockaddr_in send_addr;
socklen_t addr_length = sizeof(send_addr);
//初始化預(yù)連接的服務(wù)端地址
send_addr.sin_family = AF_INET;
send_addr.sin_port = htons(_PROT_);
send_addr.sin_addr.s_addr = inet_addr("192.168.3.198");
addr_length = sizeof(send_addr);
//總計發(fā)送 count 次數(shù)據(jù)
while (1)
{
bzero(recvBuf, sizeof(recvBuf));
//發(fā)送數(shù)據(jù)到服務(wù)遠(yuǎn)端
sendto(sock_fd, send_data, strlen(send_data), 0, (struct sockaddr *)&send_addr, addr_length);
LOG_I("socket send done");
//線程休眠一段時間
sleep(10);
// osDelay(500);
LOG_I("socket wait receive data");
//接收服務(wù)端返回的字符串
recvfrom(sock_fd, recvBuf, sizeof(recvBuf), 0, (struct sockaddr *)&send_addr, &addr_length);
LOG_I("%s:%d=>%s\n", inet_ntoa(send_addr.sin_addr), ntohs(send_addr.sin_port), recvBuf);
}
//關(guān)閉這個 socket
closesocket(sock_fd);
}
void app_socket_client_init(void)
{
osThreadAttr_t attr;
attr.name = "UDPClientTask";
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)SocketClientTask, NULL, &attr) == NULL)
{
LOG_E("[UDPClientDemo] Falied to create UDPClientTask!\n");
}
}
? ? ? ? 結(jié)果:因?yàn)槭褂玫陌姹緸?.0版本的SDK,TCP有問題,所以,這里先看UDP的結(jié)果,后續(xù)TCP會更換更改版本的SDK補(bǔ)上。
文章來源:http://www.zghlxwxcb.cn/news/detail-449799.html
?文章來源地址http://www.zghlxwxcb.cn/news/detail-449799.html
到了這里,關(guān)于鴻蒙Hi3861學(xué)習(xí)十五-Huawei LiteOS-M(Socket客戶端)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!