17 Star 59 Fork 24

Talkweb_OpenHarmony / Niobe

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
README.md 8.13 KB
一键复制 编辑 原始数据 按行查看 历史

Niobe开发板TCP联网演示

本案例程序将演示怎么在拓维Niobe WiFi IoT Core开发板上编写一个连接tcp服务器的业务程序,实现开发板联网上报数据到服务器。

简述

传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793 定义。

TCP旨在适应支持多网络应用的分层协议层次结构。 连接到不同但互连的计算机通信网络的主计算机中的成对进程之间依靠TCP提供可靠的通信服务。TCP假设它可以从较低级别的协议获得简单的,可能不可靠的数据报服务。 原则上,TCP应该能够在从硬线连接到分组交换或电路交换网络的各种通信系统之上操作。

TCP编程步骤

  1、创建一个socket,用函数socket();   2、设置socket属性,用函数setsockopt();* 可选   3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选   4、设置要连接的对方的IP地址和端口等属性;   5、连接服务器,用函数connect();   6、收发数据,用函数send()和recv(),或者read()和write();   7、关闭网络连接;

特点

(1)基于流的方式; (2)面向连接; (3)可靠通信方式; (4)在网络状况不佳的时候尽量降低系统由于重传带来的带宽开销; (5)通信连接维护是面向通信的两个端点的,而不考虑中间网段和节点

结构体详解

struct sockaddr_in {
	sa_family_t sin_family;
	in_port_t sin_port;
	struct in_addr sin_addr;
	uint8_t sin_zero[8];
};

描述:

地址和端口信息

参数:

名字 描述
sin_family 指代协议族,在socket编程中只能是AF_INET
sin_port 存储端口号(使用网络字节顺序)
sin_addr 存储IP地址,使用in_addr这个数据结构
sin_zero 为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节

示例代码如下:

	struct sockaddr_in server_addr;
	bzero(&server_addr,sizeof(server_addr)); // 初始化服务器地址
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(_PROT_);
	//server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	inet_pton(AF_INET, _SERVER_IP_, &server_addr.sin_addr);

函数详解

int WifiConnect(const char *ssid, const char *psk)

描述: 初始化网络,并连接指定wifi

参数:

名字 描述
ssid 指定wifi的账户名
psk 指定wifi的密码
int socket(int domain, int type, int protocol)

描述:

创建套接字

参数:

名字 描述
domain 地址族,也就是 IP 地址类型,常用的有 AF_INET 和 AF_INET6
type 数据传输方式/套接字类型,常用的有 SOCK_STREAM(流格式套接字/面向连接的套接字) 和 SOCK_DGRAM(数据报套接字/无连接的套接字)和SOCK_RAW(原始套接字)
protocol 传输协议,常用的有 IPPROTO_TCP 和 IPPTOTO_UDP,分别表示 TCP 传输协议和 UDP 传输协议
int connect(int fd, const struct sockaddr *addr, socklen_t len)

描述:

连接服务器

参数:

名字 描述
fd 服务器的socket
addr 存放服务端用于通信的地址和端口
len addr 结构体的大小
ssize_t recv(int fd, void *buf, size_t len, int flags)

描述:

接收数据

参数:

名字 描述
fd 客户端套接字
buf 指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据
len buf参数指向的缓冲区的长度(以字节为单位)
flags 指定消息接收的类型。此参数的值通过逻辑或零或多个以下值形成:MSG_PEEK查看传入消息。数据被视为未读数据,下一个recv()或类似函数仍将返回此数据。
ssize_t send(int fd, const void *buf, size_t len, int flags)

描述:

发送数据

参数:

名字 描述
fd 客户端套接字
buf 存放应用程序要发送数据的缓冲区
len 实际要发送的数据的字节数
flags 表示消息传输的标志,一般置0

软件设计

主要代码分析

static void TCPClientTask(void)
{
	//连接Wifi
	WifiConnect(WIFI_SSID,WIFI_PASSWORD);

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

	
	struct sockaddr_in server_addr;
	bzero(&server_addr,sizeof(server_addr)); // 初始化服务器地址
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(_PROT_);
	//server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	inet_pton(AF_INET, _SERVER_IP_, &server_addr.sin_addr);
	
	printf("connect\n");
	char str[IP_LEN];
	inet_ntop(AF_INET, &server_addr.sin_addr, str, sizeof(str));
	printf("tcp server IP_addr: %s at PORT %d\n",str,ntohs(server_addr.sin_port));

	int err_log = connect(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));      // 主动连接服务器
	if(err_log != 0)
	{
		//error_handling("connect() error!");
		perror("connet");
		printf("\nconnect is error\n");
		close(sock_fd);
		exit(-1);
	}
	
	printf("err_log ========= %d\n", err_log);
	unsigned char sendbufs[3][10]={{"0000"},{"1111"},{"2222"}};

	for(int i=0; i<3; i++)
	{
		unsigned char* send_buf=sendbufs[i];
		if(send(sock_fd, send_buf, strlen(send_buf), 0)==-1)
		{
			printf("send error\n");
			close(sock_fd);
			exit(-1);
		}

		//
		int size = recv(sock_fd, recvbuf,sizeof(recvbuf)-1,0);
		if(size>0)
		{
			printf("recv msg: %s\n",recvbuf);
		}
		usleep(1000*1000);
	}
	
	char send_buf[100]="exit";
	printf("send exit\n");
	if(send(sock_fd, send_buf, strlen(send_buf), 0)==-1)
	{
		perror("send error\n");
		close(sock_fd);
		exit(-1);
	}
	usleep(1000*1000);
	close(sock_fd);
}

编译调试

修改对接热点的账号密码

修改tcp_client.c第34行和35行的WiFi热点SSID和密码,改成自己环境中的WiFi热点。

// 默认WiFi名和密码
#define WIFI_SSID "aaa"
#define WIFI_PASSWORD "talkweb1996"

修改服务端的ip地址和端口号

修改tcp_client.c第28行和30行的端口号和ip地址,改成自己创建的服务端ip地址。

// 默认服务端的ip地址和端口号
#define _PROT_ 8800
#define _SERVER_IP_ "192.168.1.112"

修改 BUILD.gn 文件

修改 applications/app/BUILD.gn 路径中的 BUILD.gn 文件,指定 network_tcpclient_demo 参与编译。

        # "TW303_Network_mqttclient:network_mqttclient_example",
        # "TW402_APP_oled_u8g2:app_oled_u8g2_example",
        # "TW304_Network_tcpserver:network_tcpserver_demo",
         "TW304_Network_tcpclient:network_tcpclient_demo",
        # "TW305_Network_udpclient:network_udpclient_demo",

运行结果

示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志,会打印连接到的Wifi热点信息,以及服务端地址信息,和服务端通信的信息

链接wifi成功,并打印IP信息

callback function for wifi connect

WaitConnectResult:wait success[1]s
WiFi connect succeed!
begain to dhcp<-- DHCP state:Inprogress -->

<-- DHCP state:Inprogress -->

<-- DHCP state:Inprogress -->

<-- DHCP state:OK -->
server :
	server_id : 192.168.1.1
	mask : 255.255.255.0, 1
	gw : 192.168.1.1
	T0 : 7200
	T1 : 3600
	T2 : 6300
clients <1> :
	mac_idx mac             addr            state   lease   tries   rto     
	0       b4c9b9af6afe    192.168.1.114   10      0       1       3       

链接tcp服务端并进行信息通信

tcp server IP_addr: 192.168.1.112 at PORT 8800

send msg: 0000

recv msg: Hello! I'm Talkweb TCP Server!

send msg: 1111

recv msg: Hello! I'm Talkweb TCP Server!

send msg: 2222

recv msg: Hello! I'm Talkweb TCP Server!

send exit
1
https://gitee.com/talkweb_oh/niobe.git
git@gitee.com:talkweb_oh/niobe.git
talkweb_oh
niobe
Niobe
master

搜索帮助