00. 目录
文章目录
- 00. 目录
- 01. TCP概述
- 02. TCP应用场景
- 03. TCP和UDP比较
- 04. TCP相关API
- 05. TCP编程流程
- 06. 硬件设计
- 07. 软件设计
- 08. 实验现象
- 09. 附录
01. TCP概述
TCP(Transmission Control Protocol)是一种面向连接、可靠的传输层协议,旨在通过严格的传输控制机制,确保数据在IP网络中的有序、完整传输。与UDP不同,TCP通过流量控制、拥塞控制和重传机制为应用层提供高可靠性,适用于对数据准确性要求严苛的场景。
核心特点
面向连接
通信前需通过三次握手建立端到端连接,结束后通过四次挥手释放连接,确保通信双方状态同步。
可靠传输
- 数据分片与重组:将大数据分割为报文段传输,接收端按序列号重组。
- 确认应答(ACK):接收方需返回ACK确认收到数据,否则发送方重传。
- 超时重传:未收到ACK时,自动重发丢失的报文段。
顺序控制
每个报文段携带唯一序列号(Sequence Number),接收端严格按序重组数据。
流量控制
通过滑动窗口机制动态调整发送速率,防止接收方缓冲区溢出。
拥塞控制
根据网络状况动态调整发送窗口,避免网络过载(如慢启动、拥塞避免算法)。
02. TCP应用场景
- Web通信
HTTP/HTTPS(网页浏览)、SSL/TLS加密传输。 - 文件传输
FTP(文件上传下载)、SFTP(安全文件传输)。 - 邮件服务
SMTP(发送邮件)、POP3/IMAP(接收邮件)。 - 远程管理
SSH(安全远程登录)、Telnet(远程终端)。 - 数据库操作
MySQL、PostgreSQL等数据库协议依赖TCP保证事务完整性。
常见基于TCP的协议
- HTTP/HTTPS(网页传输)
- FTP/SFTP(文件传输)
- SMTP/POP3/IMAP(电子邮件)
- SSH(安全远程登录)
- MySQL/Redis(数据库协议)
03. TCP和UDP比较
特性 | TCP | UDP |
---|---|---|
连接方式 | 面向连接(三次握手/四次挥手) | 无连接 |
可靠性 | 可靠传输,自动重传 | 不可靠,不重传 |
数据顺序 | 严格保证顺序 | 不保证顺序 |
流量控制 | 滑动窗口机制 | 无 |
拥塞控制 | 动态调整发送速率 | 无 |
头部大小 | 最小20字节(可扩展) | 8字节 |
适用场景 | 数据完整性 > 实时性 | 实时性 > 可靠性 |
04. TCP相关API
以下 TCP 接口位于 vendor\hisi\hi3861\hi3861\third_party\lwip_sack\include\sockets.h。
-
socket()
-
bind()
-
accept()
-
shutdown()
-
getpeername()
-
getsockopt()
&setsockopt()
-
close()
-
read()
,readv()
,write()
,writev()
-
recv()
-
send()
,sendmsg()
,sendto()
-
select()
-
fcntl()
05. TCP编程流程
5.1 新建socket
int sock_fd;//创建socket
if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{perror("create socket failed!\r\n");exit(1);
}
5.2 配置将要连接的服务器信息(端口和IP)
#define TCP_SERVER_ADRESS "192.168.31.170" // 要连接TCP服务器地址
#define TCP_PORT 8888 // 要连接TCP服务器端口号int addr_length;//服务器的地址信息
struct sockaddr_in send_addr;//初始化预连接的服务端地址
send_addr.sin_family = AF_INET;
send_addr.sin_port = htons(TCP_PORT);
send_addr.sin_addr.s_addr = inet_addr(TCP_SERVER_ADRESS);
addr_length = sizeof(send_addr);
5.3 连接服务器
connect(sock_fd, (struct sockaddr *)&send_addr, addr_length);
5.4 发送数据
static const char *send_data = "Hello! I'm BearPi-HM_Nano TCP Client!\r\n";while (1)
{······//发送数据到服务远端int ret;if((ret = send(sock_fd, send_data, strlen(send_data), 0)) == -1){perror("send:");}······
}
5.5 接收数据
char recvBuf[512];int ret;
//接收服务端返回的字符串
if((ret = recv(sock_fd, recvBuf, sizeof(recvBuf), 0)) == -1)
{printf("recv error\r\n");
}
printf("recv:%s\r\n", recvBuf);
5.6 关闭连接
//关闭这个 socket
closesocket(sock_fd);
06. 硬件设计
由于 Hi3861 内置 WIFI 功能,所以直接在开发板上使用即可,无需额外连接
07. 软件设计
bsp_wifi.h
#ifndef __BSP_WIFI_H__
#define __BSP_WIFI_H__#include "cmsis_os2.h"
#include "hi_io.h"
#include "hi_gpio.h"
#include "wifi_error_code.h"
#include "wifi_device.h"//函数声明
WifiErrorCode WiFi_createHotSpots(const char *ssid, const char *psk);WifiErrorCode WiFi_connectHotspots(const char *ssid, const char *psk);#endif /* __BSP_WIFI_H__ */
bsp_wifi.c
#include <unistd.h>
#include <stdio.h>
#include <string.h>#include "wifi_device.h"
#include "wifi_hotspot.h"
#include "lwip/netifapi.h"
#include "lwip/netif.h"
#include "lwip/ip4_addr.h"
#include "lwip/api_shell.h"
#include "bsp_wifi.h"//WIFI通道
#define WIFI_CHANNEL 5#define DEF_TIMEOUT 15#define SELECT_WLAN_PORT "wlan0"//STA 连接状态结果
int g_ConnectState = 0;struct netif *g_lwip_netif = NULL;//----------------------------WIFI AP----------------------------------
/** Hotspot state change */
void OnHotspotStateChangedCallbak(int state)
{printf("OnHotspotStateChangedCallbak: state is %d.\n", state);if (WIFI_HOTSPOT_ACTIVE == state){printf("wifi hotspot active\n");}else{printf("wifi hotspot noactive\n");}
}/** Station connected */
void OnHotspotStaJoinCallbak(StationInfo *info)
{static char macAddr[32] = {0};static unsigned char *mac = NULL;if (NULL == info){printf("OnHotspotStaJoinCallbak is NULL\n");}else{mac = info->macAddress;snprintf(macAddr, sizeof(macAddr), "%02X:%02X:%02X:%02X:%02X:%02X",mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);printf("OnHotspotStaJoinCallbak: mac: %s reason: %d\n", macAddr, info->disconnectedReason);}
}/** Station disconnected */
void OnHotspotStaLeaveCallbak(StationInfo *info)
{static char macAddr[32] = {0};static unsigned char *mac = NULL;if (NULL == info){printf("OnHotspotStaLeaveCallbak is NULL\n");}else{mac = info->macAddress;snprintf(macAddr, sizeof(macAddr), "%02X:%02X:%02X:%02X:%02X:%02X",mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);printf("OnHotspotStaLeaveCallbak: mac: %s reason: %d\n", macAddr, info->disconnectedReason);}}//创建Wifi热点
WifiErrorCode WiFi_createHotSpots(const char *ssid, const char *psk)
{WifiErrorCode ret;static WifiEvent event;static HotspotConfig config;printf("Start Initialization of WiFI AP Mode\r\n");//注册WIFI事件的回调函数event.OnHotspotStaJoin = OnHotspotStaJoinCallbak;event.OnHotspotStaLeave = OnHotspotStaLeaveCallbak;event.OnHotspotStateChanged =OnHotspotStateChangedCallbak;ret = RegisterWifiEvent(&event);if (WIFI_SUCCESS != ret){printf("RegisterWifiEvent failed....\n");return -1;}printf("RegisterWifiEvent OK .....\n");//设置热点strcpy(config.ssid, ssid);strcpy(config.preSharedKey, psk);config.band = HOTSPOT_BAND_TYPE_2G;config.channelNum = WIFI_CHANNEL;config.securityType = WIFI_SEC_TYPE_PSK;ret = SetHotspotConfig(&config);if (WIFI_SUCCESS != ret){printf("SetHotspotConfig failed....\n");return -1;}printf("SetHotspotConfig OK....\n");//启动WIFI AP模式ret = EnableHotspot();if (WIFI_SUCCESS != ret){printf("EnableHotspot failed...\n");return -1;}printf("EnableHotspot OK ....\n");//检查热点模式是否使能if (WIFI_HOTSPOT_ACTIVE != IsHotspotActive()){printf("IsHotspotActive failed....\n");return -1;}printf("IsHotspotActive OK .....\n");
}//----------------------------WIFI STA----------------------------------/** Connection state change */
void staOnWifiConnectionChanged(int state, WifiLinkedInfo *info)
{if (state > 0){g_ConnectState = 1;printf("staOnWifiConnectionChanged state: %d\n", state);}else{printf("staOnWifiConnectionChanged failed state: %d\n", state);}}/** Scan state change */
void staOnWifiScanStateChanged(int state, int size)
{printf("staOnWifiScanStateChanged state: %d size: %d\n", state, size);
}/** Hotspot state change */
void staOnHotspotStateChanged(int state)
{printf("staOnHotspotStateChanged state: %d\n", state);
}/** Station connected */
void staOnHotspotStaJoin(StationInfo *info)
{printf("staOnHotspotStaJoin STA Join AP\n");
}/** Station disconnected */
void staOnHotspotStaLeave(StationInfo *info)
{printf("staOnHotspotStaLeave..\n");
}//STA模式 连接WIFI
WifiErrorCode WiFi_connectHotspots(const char *ssid, const char *psk)
{WifiErrorCode ret;static WifiEvent event;static WifiDeviceConfig config;int result;int timeout;printf("---------------WIFI STA Mode------------\n");//1. 注册WIFI事件event.OnHotspotStaJoin = staOnHotspotStaJoin;event.OnHotspotStaLeave = staOnHotspotStaLeave;event.OnHotspotStateChanged = staOnWifiScanStateChanged;event.OnWifiConnectionChanged = staOnWifiConnectionChanged;event.OnWifiScanStateChanged = staOnWifiScanStateChanged;ret = RegisterWifiEvent(&event);if (WIFI_SUCCESS != ret){printf("RegisterWifiEvent failed....\n");return -1;}else{printf("RegisterWifiEvent OK....\n");}//2. 使能WIFIret = EnableWifi();if (WIFI_SUCCESS != ret){printf("EnableWifi failed...\n");return -1;}//3. 判断WIFI是否激活if (WIFI_STA_ACTIVE != IsWifiActive()){printf("IsWifiActive is not actived..\n");return -1;}//4. 配置连接热点信息strcpy(config.ssid, ssid);strcpy(config.preSharedKey, psk);config.securityType = WIFI_SEC_TYPE_PSK;ret = AddDeviceConfig(&config, &result);if (WIFI_SUCCESS != ret){printf("AddDeviceConfig failed....\n");return -1;}//5. 连接到热点if (WIFI_SUCCESS == ConnectTo(result)){printf("ConnectTo OK.....\n");}else{printf("ConnectTo failed....\n");return -1;}//6. 等待连接结果timeout = DEF_TIMEOUT;while(timeout > 0){sleep(1);timeout--;if (1 == g_ConnectState){printf("Connect to %s OK ....\n", ssid);break;}}if (timeout <= 0){printf("Connect to %s timeout.....\n", ssid);return -1;}//7. 获取网络接口g_lwip_netif = netifapi_netif_find(SELECT_WLAN_PORT);//8. 启动DHCPif (NULL != g_lwip_netif){dhcp_start(g_lwip_netif);printf("dhcp_start begin dhcp....\n");}//9. 等待DHCPfor (;;){if (dhcp_is_bound(g_lwip_netif) == ERR_OK){//打印获取到的IP信息netifapi_netif_common(g_lwip_netif, dhcp_clients_info_show, NULL);break;}printf("DHCP IP InProgress.....\n");sleep(1);}//10. 执行其它操作}
template.c
#include <stdio.h>
#include <unistd.h>#include "ohos_init.h"
#include "cmsis_os2.h"#include "bsp_wifi.h"
#include "lwip/sockets.h"#define TASK_STACK_SIZE 1024static const char *data = "hello shenzhen";//任务1ID
osThreadId_t task1_id;
osThreadId_t task2_id;//线程回调入口函数
void task1 (void *argument)
{int sockfd = -1;int ret = -1;char buf[128];struct sockaddr_in addr;//连接到WIFIWiFi_connectHotspots("IOT", "iot12345678");//创建套接字sockfd = socket(AF_INET, SOCK_STREAM, 0);if (-1 == sockfd){perror("socket");return;}printf("sockfd = %d\n", sockfd);//初始化预连接的服务端地址memset(&addr, 0, sizeof(addr));addr.sin_family = AF_INET;addr.sin_port = htons(10086);addr.sin_addr.s_addr = inet_addr("192.168.16.51");//连接到服务端ret = connect(sockfd, &addr, sizeof(addr));if (-1 == ret){perror("connect");return;}printf("connect to server OK....\n");//数据发送和接收while(1){ret = send(sockfd, data, strlen(data), 0);if (-1 == ret){perror("send");break;}printf("send: %s ret: %d\n", data, ret);memset(buf, 0, sizeof(buf));ret = recv(sockfd, buf, sizeof(buf), 0);if (-1 == ret){perror("recv");break;}printf("recv: %s ret: %d\n", buf, ret);sleep(1);}//关闭连接closesocket(sockfd);}/*** @description: 初始化并创建任务* @param {*}* @return {*}*/
static void template_demo(void)
{ osThreadAttr_t attr;attr.name = "task1"; //任务名称attr.attr_bits = osThreadDetached; //分离状态attr.cb_mem = NULL;attr.cb_size = 0;attr.stack_mem = NULL;attr.stack_size = TASK_STACK_SIZE * 10;attr.priority = osPriorityNormal;//创建任务1task1_id = osThreadNew(task1, NULL, &attr);if (NULL != task1_id){printf("任务1创建OK task1_id = %d\n", task1_id);}}
SYS_RUN(template_demo);