0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

第十三章 W55MH32 UPnP端口转发示例

W55MH32 ? 来源:W55MH32 ? 作者:W55MH32 ? 2025-07-24 10:28 ? 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

单芯片解决方案,开启全新体验——W55MH32 高性能以太网单片机

W55MH32是WIZnet重磅推出的高性能以太网单片机,它为用户带来前所未有的集成化体验。这颗芯片将强大的组件集于一身,具体来说,一颗W55MH32内置高性能Arm? Cortex-M3核心,其主频最高可达216MHz;配备1024KB FLASH与96KB SRAM,满足存储与数据处理需求;集成TOE引擎,包含WIZnet全硬件TCP/IP协议栈、内置MAC以及PHY,拥有独立的32KB以太网收发缓存,可供8个独立硬件socket使用。如此配置,真正实现了All-in-One解决方案,为开发者提供极大便利。

在封装规格上,W55MH32提供了两种选择:QFN100和QFN68。

W55MH32L采用QFN100封装版本,尺寸为12x12mm,其资源丰富,专为各种复杂工控场景设计。它拥有66个GPIO、3个ADC、12通道DMA、17个定时器、2个I2C、5个串口、2个SPI接口(其中1个带I2S接口复用)、1个CAN、1个USB2.0以及1个SDIO接口。如此丰富的外设资源,能够轻松应对工业控制中多样化的连接需求,无论是与各类传感器、执行器的通信,还是对复杂工业协议的支持,都能游刃有余,成为复杂工控领域的理想选择。同系列还有QFN68封装的W55MH32Q版本,该版本体积更小,仅为8x8mm,成本低,适合集成度高的网关模组等场景,软件使用方法一致。更多信息和资料请进入http://www.w5500.com/网站或者私信获取。

此外,本W55MH32支持硬件加密算法单元,WIZnet还推出TOE+SSL应用,涵盖TCP SSL、HTTP SSL以及 MQTT SSL等,为网络通信安全再添保障。

为助力开发者快速上手与深入开发,基于W55MH32L这颗芯片,WIZnet精心打造了配套开发板。开发板集成WIZ-Link芯片,借助一根USB C口数据线,就能轻松实现调试、下载以及串口打印日志等功能。开发板将所有外设全部引出,拓展功能也大幅提升,便于开发者全面评估芯片性能。

若您想获取芯片和开发板的更多详细信息,包括产品特性、技术参数以及价格等,欢迎访问官方网页:http://www.w5500.com/,我们期待与您共同探索W55MH32的无限可能。

wKgZO2iBiBmAe3DyAACpGc5mWX8613.png

第十三章 W55MH32 UPnP端口转发示例

本篇文章,我们将详细介绍如何在W55MH32芯片上面实现UPnP协议。使用W55MH32的TOE引擎,我们只需进行简单的socket编程寄存器读写,便可轻松实现以太网应用。接下来我们通过实战例程,为大家讲解如何使用TOE引擎实现UPnP协议的端口转发功能。

该例程用到的其他网络协议,例如DHCP,请参考相关章节。有关W55MH32的初始化过程,请参考Network Install章节,这里将不再赘述。

1 UPnP协议简介

UPnP(Universal Plug and Play)协议是一种支持设备在局域网中实现自动发现和通信的网络协议。其端口转发功能由IGD Profile提供,允许局域网设备动态请求路由器为其开放指定的端口,以实现外部设备访问内部服务。这种功能消除了手动配置端口转发的复杂性,特别适用于需要穿透NAT(网络地址转换)环境的应用场景。

IGDInternet Gateway Device,互联网网关设备)是UPnP(Universal Plug and Play)协议的一部分,主要用于管理网络中的网关设备(如路由器)的服务和资源。IGD扩展定义了一套标准接口,允许局域网设备与网关设备通信,动态配置网络设置,例如端口转发、带宽管理和连接状态查询等。

2 UPnP协议特点

自动化配置:无需用户手动设置,减少了配置错误的风险。

动态灵活:端口映射规则可以根据需求动态添加或删除。

设备友好:支持即插即用,简化了设备的联网和部署过程。

跨设备兼容:UPnP基于标准化协议,广泛支持各种设备和平台。

3 UPnP应用场景

通过UPnP端口转发功能,我们可以使用W55MH32实现以下功能:

远程访问:将外部请求转发到局域网设备(如NAS、监控摄像头),实现外部远程访问内部设备。

远程控制:外部设备通过UPnP转换的端口,可以实现远程控制局域网内部设备(智能门锁、灯光控制器)。

4 UPnP设置端口转发的工作流程

设备发现:W55MH32通过SSDP(Simple Service Discovery Protocol)向局域网中发送组播请求(HTTP M-SEARCH报文),搜索支持IGD的网关设备。

获取服务描述:W55MH32访问网关设备(路由器)获取服务描述文件,了解支持的服务和接口。

订阅IGD事件:通过事件订阅,W55MH32可以在不主动轮询的情况下,接收实时通知。

调用服务接口:使用UPnP的SOAT消息调用IGD提供的端口映射接口。

数据交互测试:外部通过访问映射的端口及路由器地址和局域网内部设备进行通信。

5报文讲解

设备搜索

上文我们提到,设备搜索时使用SSDP协议,SSDP(Simple Service Discovery Protocol)是 UPnP协议中的关键协议,用于设备发现和服务发布。它通过HTTP over UDP的形式在局域网内广播和接收报文,采用多播地址 239.255.255.250和端口 1900。

SSDP报文主要分为以下几类:

NOTIFY消息(设备主动广播通知):用于设备向网络通告自己的存在或离线状态。

M-SEARCH消息(客户端主动搜索):客户端发送搜索请求以发现设备或服务。

HTTP/1.1响应消息(设备对 M-SEARCH的响应):设备对搜索请求的响应,提供设备描述文件的位置及服务信息。

SSDP报文基于HTTP协议,有固定的格式,主要包括以下字段:

HOST:目标地址和端口,固定为 239.255.255.250:1900。

MAN:用于标识搜索消息,固定为 "ssdp:discover"(仅在 M-SEARCH中使用)。

MX:最大响应时间,指定设备在多长时间内响应(单位:秒)。

ST:搜索目标,标识要查找的设备类型或服务类型。

NT:通知类型,表示设备或服务的类型(在 NOTIFY消息中使用)。

USN:唯一服务名称,设备或服务的唯一标识符。

LOCATION:设备描述文件的 URL,包含设备的详细信息。

CACHE-CONTROL:设备信息的缓存时间,表示在多长时间内有效。

M-SEARCH请求报文实例:

M-SEARCH * HTTP/1.1
Host:239.255.255.250:1900
ST:urn:schemas-upnp-org:device:InternetGatewayDevice:1
Man:"ssdp:discover"
MX:3

字段解析:

M-SEARCH * HTTP/1.1:表明是一个搜索请求。

Host:多播地址和端口。

ST:搜索目标类型,这里是IGD设备。

MX:最大响应事件,设备需要在3秒内返回响应。

Man:搜索请求类型,固定。

M-SEARCH响应报文实例:

HTTP/1.1 200 OK
CACHE-CONTROL: max-age=60
DATE: Tue, 07 Jan 2025 06:43:49 GMT
EXT:
LOCATION: http://192.168.100.1:1900/igd.xml
SERVER: vxWorks/5.5 UPnP/1.0 TL-WR886N/6.0
ST: urn:schemas-upnp-org:device:InternetGatewayDevice:1
USN: uuid:8c15e41f-3d83-41c1-b35d-5D2A64377DE9::urn:schemas-upnp-org:device:InternetGatewayDevice:1

HTTP/1.1 200 OK:表示响应成功。

CACHE-CONTROL:响应有效时间为60秒。

DATE:响应的时间戳。

EXT:保留字段,目前为空。

LOCATION:设备描述文件的URL。

SERVER:设备的操作系统,UPnP版本和设备名称。

ST:搜索目标类型,和请求中的ST字段一致。

USN:唯一设备标识符。

获取设备标识符

这一步会通过HTTP GET方式去请求xml文件,有关HTTP GET报文以及HTTP响应报文这里不过多讲解,有兴趣的可以参考 HTTP Client章节。

请求示例:

GET /igd.xml HTTP/1.1
Accept: text/xml, application/xml
User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)
Host: 192.168.100.1:1900
Connection: Keep-Alive
Cache-Control: no-cache
Pragma: no-cache

响应示例:

HTTP/1.1 200 OK
Content-Type: text/xml;charset=UTF-8
Content-Length: 2580
Connection: close
Cache-control: no-cache




1
0


urn:schemas-upnp-org:device:InternetGatewayDevice:1
http://192.168.100.1:80 
Wireless N Router TL-WR886N
TP-LINK
http://www.tp-link.com.cn
TL-WR886N 6.0
TL-WR886N
6.0
uuid:8c15e41f-3d83-41c1-b35d-5D2A64377DE9
123456789001


urn:schemas-upnp-org:service:Layer3Forwarding:1
urn:upnp-org:serviceId:L3Forwarding1
/l3f
/l3f
/l3f.xml




urn:schemas-upnp-org:device:WANDevice:1
WAN Device
TP-LINK
http://www.tp-link.com.cn
WAN Device
WAN Device
1.0

12345678900001
uuid:8c15e41f-3d83-41c1-b35d-5D2A64377DE9
123456789001


urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1
urn:upnp-org:serviceId:WANCommonInterfaceConfig
/ifc
/ifc
/ifc.xml




urn:schemas-upnp-org:device:WANConnectionDevice:1
WAN Connection Device
TP-LINK
http://www.tp-link.com.cn
WAN Connection Device
WAN Connection Device
1.0

12345678900001
uuid:8c15e41f-3d83-41c1-b35d-5D2A64377DE9
123456789001


urn:schemas-upnp-org:service:WANIPConnection:1
urn:upnp-org:serviceId:WANIPConnection
/ipc
/ipc
/ipc.xml







订阅IGD事件

通过HTTP SUBSCRIBE订阅IGD事件,示例:

SUBSCRIBE /ipc HTTP/1.1
Host: 192.168.100.1:1900
USER-AGENT: Mozilla/4.0 (compatible; UPnP/1.1; Windows NT/5.1)
CALLBACK: 
NT: upnp:event
TIMEOUT: Second-1800

响应示例:

HTTP/1.1 200 OK
Content-Type: text/xml;charset=UTF-8
Content-Length: 0
Connection: close
Cache-control: no-cache
Server: vxWorks/5.5 UPnP/1.0 TL-WR886N/6.0
Timeout: Second-1800
SID: uuid:82-2150160019

添加映射端口报文

例如,我们想映射TCP协议的内部端口8000到外部端口1000上,可以按照以下示例进行HTTP请求:

POST /ipc HTTP/1.1
Content-Type: text/xml; charset="utf-8"
SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping"
User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)
Host: 192.168.100.1:1900
Content-Length: 1131
Connection: Keep-Alive
Cache-Control: no-cache
Pragma: no-cache








1000

TCP

8000

192.168.100.101
1
W5500_uPnPGetway
0


主要字段的描述如下:

m:AddPortMapping:添加端口映射

NewExternalPort:外部端口号

NewProtocol:协议类型

NewInternalPort:内部端口号

NewInternalClient:内部地址

响应内容:

HTTP/1.1 200 OK
Content-Type: text/xml;charset=UTF-8
Content-Length: 289
Connection: close
Cache-control: no-cache
Server: vxWorks/5.5 UPnP/1.0 TL-WR886N/6.0


删除端口映射报文

例如,我们想删除上面映射的1000端口,可以按照以下示例进行HTTP请求:

POST /ipc HTTP/1.1
Content-Type: text/xml; charset="utf-8"
SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#DeletePortMapping"
User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)
Host: 192.168.100.1:1900
Content-Length: 604
Connection: Keep-Alive
Cache-Control: no-cache
Pragma: no-cache





1000
TCP

主要字段的描述如下:

m:DeletePortMapping:删除端口映射

NewExternalPort:外部端口号

NewProtocol:协议类型

NewRemoteHost:外部访问来源,可以为空

6实现过程

在这个例程中,我们实现了通过串口控制LED灯开关、获取和设置网络地址信息、TCP和UDP回环数据测试以及UPnP添加映射端口和删除映射端口的功能。

注意:测试实例需要W55MH32接入在支持UPnP端口转发的路由器下。

步骤1:设置以太网缓存大小

static uint8_t  tx_size[_WIZCHIP_SOCK_NUM_] = {4, 4, 2, 1, 1, 1, 1, 2};
static uint8_t  rx_size[_WIZCHIP_SOCK_NUM_] = {4, 4, 2, 1, 1, 1, 1, 2};
/* socket rx and tx buff init */
wizchip_init(tx_size, rx_size);

在这里我们给socket0-7的收发缓存分别设置为4KB,4KB,2KB,1KB,1KB,1KB,1KB,2KB。

其中socket0用于UPnP协议处理,socket1用于TCP和UDP回环处理,socket2用于监听IGD事件。

步骤2:LED控制函数注册

UserLED_Control_Init(set_user_led_status);

set_user_led_status()函数为控制LED的函数,具体内容如下:

/*void set_user_led_status(uint8_t val)
{
 if (val)
 {
     GPIO_SetBits(GPIOD, GPIO_Pin_14);
 }
 else
 {
     GPIO_ResetBits(GPIOD, GPIO_Pin_14);
 }
}

步骤3:搜索UPnP设备

do
{
   printf("Send SSDP.. rn");
}   while (SSDPProcess(SOCKET_ID) != 0); // SSDP Search discovery

/**< SSDP Header */
unsigned char SSDP[] = "
M-SEARCH * HTTP/1.1rn
Host:239.255.255.250:1900rn
ST:urn:schemas-upnp-org:device:InternetGatewayDevice:1rn
Man:"ssdp:discover"rn
MX:3rn
rn
";
/**
* @brief This function processes the SSDP message.
* @return 0: success, -1: reply packet timeout, 1: received SSDP parse error
*/
signed char SSDPProcess(SOCKET sockfd)
{
 char          ret_value     = 0;
 long          endTime       = 0;
 unsigned char mcast_addr[4] = {239, 255, 255, 250};
 // unsigned char_t_t mcast_mac[6] = {0x28, 0x2C, 0xB2, 0xE9, 0x42, 0xD6};
 unsigned char  recv_addr[4];
 unsigned short recv_port;
 // UDP Socket Open
 close(sockfd);
 socket(sockfd, Sn_MR_UDP, PORT_SSDP, 0); /*Initialize socket for socket 0*/
 while (getSn_SR(sockfd) != SOCK_UDP);
#ifdef UPNP_DEBUG
 printf("%srn", SSDP);
#endif
 // Send SSDP
 if (sendto(sockfd, SSDP, strlen((char *)SSDP), mcast_addr, 1900) <= 0)
     printf("SSDP Send error!!!!!!!rn");
 // Receive Reply
 memset(recv_buffer, '', RECV_BUFFER_SIZE);
 endTime = my_time + 3;
 while (recvfrom(sockfd, (unsigned char *)recv_buffer, RECV_BUFFER_SIZE, recv_addr, &recv_port) <= 0 && my_time < endTime); // Check Receive Buffer
 if (my_time >= endTime)
 {                                                                                                                          // Check Timeout
     close(sockfd);
     return -1;
 }
 // UDP Socket Close
 close(sockfd);
#ifdef UPNP_DEBUG
 printf("rnReceiveDatarn%srn", recv_buffer);
#endif
 // Parse SSDP Message
 if ((ret_value = parseSSDP(recv_buffer)) == 0)
     UPnP_Step = 1;
 return ret_value;
}

在这个函数中,主要是使用SSDP协议搜索IGD设备,发送报文和前面我们介绍的一致。

步骤4:获取IGD设备描述

if (GetDescriptionProcess(SOCKET_ID) == 0) // GET IGD description
{
   printf("GetDescription Success!!rn");
}
else
{
   printf("GetDescription Fail!!rn");
}

/**
* @brief This function gets the description message from IGD(Internet Gateway Device).
* @return 0: success, -2: Invalid UPnP Step, -1: reply packet timeout, 1: received xml parse error
*/
signed char GetDescriptionProcess(
SOCKET sockfd /**< a socket number. */
)
{
char           ret_value = 0;
long           endTime   = 0;
unsigned long  ipaddr;
unsigned short port;
// Check UPnP Step
if (UPnP_Step < 1) return -2;
// Make HTTP GET Header
memset(send_buffer, '', SEND_BUFFER_SIZE);
MakeGETHeader(send_buffer);
#ifdef UPNP_DEBUG
printf("%srn", send_buffer);
#endif
ipaddr = inet_addr((unsigned char *)descIP);
ipaddr = swapl(ipaddr);
port   = ATOI(descPORT, 10);
// Connect to IGD(Internet Gateway Device)
close(sockfd);
socket(sockfd, Sn_MR_TCP, PORT_UPNP, Sn_MR_ND); /*Open a port of the socket*/
while (getSn_SR(sockfd) != SOCK_INIT)
{
 delay_ms(100);
}
if (connect(sockfd, (unsigned char *)&ipaddr, port) == 0)
 printf("TCP Socket Error!!rn");
// Send Get Discription Message
while ((getSn_SR(sockfd) != SOCK_ESTABLISHED));
send(sockfd, (void *)send_buffer, strlen(send_buffer));
// Receive Reply
memset(recv_buffer, '', RECV_BUFFER_SIZE);
delay_ms(500);
endTime = my_time + 3;
while (recv(sockfd, (void *)recv_buffer, RECV_BUFFER_SIZE) <= 0 && my_time < endTime); // Check Receive Buffer
if (my_time >= endTime)
{                                                                                      // Check Timeout
 close(sockfd);
 return -1;
}
// TCP Socket Close
close(sockfd);
#ifdef UPNP_DEBUG
printf("rnReceiveDatarn%srn", recv_buffer);
#endif
// Parse Discription Message
if ((ret_value = parseDescription(recv_buffer)) == 0) UPnP_Step = 2;
return ret_value;
}

请求报文通过MakeGETHeader()函数进行组包,具体报文如下:

/**
* @brief   This function makes the HTTP GET header.
* @param   dest:Target string pointer
* @return  none
*/
void MakeGETHeader(char *dest)
{
   char local_port[6] = {''};
   strcat(dest, "GET ");
   strcat(dest, descLOCATION);
   strcat(dest, " HTTP/1.1rn");
   strcat(dest, "Accept: text/xml, application/xmlrn");
   strcat(dest, "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)rn");
   strcat(dest, "Host: ");
   strcat(dest, descIP);
   sprintf(local_port, ":%s", descPORT);
   strcat(dest, local_port);
   strcat(dest, "rnConnection: Keep-AlivernCache-Control: no-cachernPragma: no-cachernrn");
}

然后将接收到的内容,通过parseDescription()函数进行解析,如果设备描述中不支持WANIPConnection服务,则说明不支持端口映射,返回错误。

parseDescription()函数内容如下:

/**
* @brief This function parses the received description message from IGD(Internet Gateway Dev
* @return 0: success, 1: received xml parse error
*/
signed char parseDescription(
   const char *xml /**< string for parse */
)
{
   const char controlURL_[]  = "";
   const char eventSubURL_[] = "";
   char      *URL_start = 0, *URL_end = 0;
   if (parseHTTP(xml) != 0) return 1;
   //printf("rn%srn", xml);
   // Find Control URL("/etc/linuxigd/gateconnSCPD.ctl")
   if ((URL_start = strstr(xml, "urn:schemas-upnp-org:service:WANIPConnection:1")) == NULL) retur
   if ((URL_start = strstr(URL_start, controlURL_)) == NULL) return 1;
   if ((URL_end = strstr(URL_start, "")) == NULL) return 1;
   strncpy(controlURL, URL_start + strlen(controlURL_), URL_end - URL_start - strlen(controlURL_)
   // Find Eventing Subscription URL("/etc/linuxigd/gateconnSCPD.evt")
   if ((URL_start = strstr(xml, "urn:schemas-upnp-org:service:WANIPConnection:1")) == NULL) retur
   if ((URL_start = strstr(URL_start, eventSubURL_)) == NULL) return 1;
   if ((URL_end = strstr(URL_start, "")) == NULL) return 1;
   strncpy(eventSubURL, URL_start + strlen(eventSubURL_), URL_end - URL_start - strlen(eventSubUR
   return 0;
}

步骤5:订阅IGD事件

if (SetEventing(SOCKET_ID) == 0) // Subscribes IGD event messages
{
   printf("SetEventing Success!!rn");
}
else
{
   printf("SetEventing Fail!!rn");
}

SetEventing()函数内容如下:

/**
* @brief This function subscribes to the eventing message from IGD(Internet Gateway Device).
* @return 0: success, -2: Invalid UPnP Step, -1: reply packet timeout
*/
signed char SetEventing(
 SOCKET sockfd /**< a socket number. */
)
{
 long           endTime = 0;
 unsigned long  ipaddr;
 unsigned short port;
 // Check UPnP Step
 if (UPnP_Step < 2) return -2;
 // Make Subscription message
 memset(send_buffer, '', SEND_BUFFER_SIZE);
 MakeSubscribe(send_buffer, PORT_UPNP_EVENTING);
#ifdef UPNP_DEBUG
 printf("%srn", send_buffer);
#endif
 ipaddr = inet_addr((unsigned char *)descIP);
 ipaddr = swapl(ipaddr);
 port   = ATOI(descPORT, 10);
 // Connect to IGD(Internet Gateway Device)
 close(sockfd);
 socket(sockfd, Sn_MR_TCP, PORT_UPNP, Sn_MR_ND); /*Open a port of the socket*/
 while (getSn_SR(sockfd) != SOCK_INIT)
 {
     delay_ms(100);
 }
 if (connect(sockfd, (unsigned char *)&ipaddr, port) == 0)
     printf("TCP Socket Error!!rn");
 // Send Get Discription Message
 while ((getSn_SR(sockfd) != SOCK_ESTABLISHED));
 send(sockfd, (void *)send_buffer, strlen(send_buffer));
 // Receive Reply
 memset(recv_buffer, '', RECV_BUFFER_SIZE);
 delay_ms(500);
 endTime = my_time + 3;
 while (recv(sockfd, (void *)recv_buffer, RECV_BUFFER_SIZE) <= 0 && my_time < endTime); // Check Receive Buffer
 if (my_time >= endTime)
 {                                                                                      // Check Timeout
     close(sockfd);
     return -1;
 }
 // TCP Socket Close
 close(sockfd);
#ifdef UPNP_DEBUG
 printf("rnReceiveDatarn%srn", recv_buffer);
#endif
 return parseHTTP(recv_buffer);
}

请求报文通过MakeSubscribe()函数进行组包,具体报文如下:

/**
* @brief   This function makes the Subscription message.
* @param   dest:Target string pointer
* @param   listen_port:Listen port
* @return  none
*/
void MakeSubscribe(char *dest, const unsigned int listen_port)
{
   char          local_port[6] = {''}, ipaddr[16] = {''};
   unsigned char ip[4];
   strcat(dest, "SUBSCRIBE ");
   strcat(dest, eventSubURL);
   strcat(dest, " HTTP/1.1rn");
   strcat(dest, "Host: ");
   strcat(dest, descIP);
   sprintf(local_port, ":%s", descPORT);
   strcat(dest, local_port);
   strcat(dest, "rnUSER-AGENT: Mozilla/4.0 (compatible; UPnP/1.1; Windows NT/5.1)rn");
   strcat(dest, "CALLBACK: ", listen_port);
   strcat(dest, local_port);
   strcat(dest, "rnNT: upnp:eventrnTIMEOUT: Second-1800rnrn");
}

最后,通过parseHTTP()函数解析HTTP响应报文,判断是否订阅成功。

parseHTTP()函数如下:

/*-----String Parse Functions-----*/
/**
 * @brief This function parses the HTTP header.
 * @return 0: success, 1: received xml parse error
 */
signed char parseHTTP(
   const char *xml /**< string for parse */
)
{
   char *loc = 0;
   if (strstr(xml, "200 OK") != NULL)
       return 0;
   else
   {
       loc = strstr(xml, "rn");
       memset(content, '', CONT_BUFFER_SIZE);
       strncpy(content, xml, loc - xml);
       printf("rnHTTP Error:rn%srnrn", content);
       return 1;
   }
}

步骤6:执行UPnP主程序

Main_Menu(SOCKET_ID, SOCKET_ID + 1, SOCKET_ID + 2, ethernet_buf, tcps_port, udps_port); // Main menu

/**
* @brief   Display/Manage a Menu on HyperTerminal Window
* @param   sn: use for SSDP; sn2: use for run tcp/udp loopback; sn3: use for listenes IGD event message
* @param   buf: use for tcp/udp loopback rx/tx buff; tcps_port: use for tcp loopback listen; udps_port: use 
for udp loopback receive
* @return  none
*/
void Main_Menu(uint8_t sn, uint8_t sn2, uint8_t sn3, uint8_t *buf, uint16_t tcps_port, uint16_t udps_port)
{
   static char           choice[3];
   static char           msg[256], ipaddr[12], protocol[4];
   static unsigned short ret, external_port, internal_port;
   static uint8_t        bTreat;
   static uint8_t        Sip[4];
   while (1)
   {
       /* Display Menu on HyperTerminal Window */
       bTreat = RESET;
       printf("rn====================== WIZnet Chip Control Point ===================rn");
       printf("This Application is basic example of UART interface withrn");
       printf("Windows Hyper Terminal. rn");
       printf("rn==========================================================rn");
       printf("                          APPLICATION MENU :rn");
       printf("rn==========================================================rnn");
       printf(" 1 - Set LED on rn");
       printf(" 2 - Set LED off rn");
       printf(" 3 - Show network settingrn");
       printf(" 4 - Set  network settingrn");
       printf(" 5 - Run TCP Loopbackrn");
       printf(" 6 - Run UDP Loopbackrn");
       printf(" 7 - UPnP PortForwarding: AddPortrn");
       printf(" 8 - UPnP PortForwarding: DeletePortrn");
       printf("Enter your choice : ");
       memset(choice, 0, sizeof(choice));
       scanf("%s", choice);
       printf("%crn", choice[0]);

在这里会执行一个用户选项菜单,选项1和2控制LED开关,选项3和4打印和设置网络地址信息,选项5运行一个TCP回环测试程序(回环测试程序可参考TCP Server章节),选项6运行一个UDP回环测试程序(回环测试程序可参考UDP章节)。选项7添加一个UPnP端口映射表,选项8删除一个UPnP端口映射表。这里我们主要讲解UPnP相关的选项7和选项8。

步骤7:添加一个UPnP端口映射表

代码如下:

if (choice[0] == '7')
{
 bTreat = SET;
 printf("rnType a Protocol(TCP/UDP) : ");
 memset(msg, 0, sizeof(msg));
 scanf("%s", msg);
 printf("%srn", msg);
 strncpy(protocol, msg, 3);
 protocol[3] = '';
 printf("rnType a External Port Number : ");
 memset(msg, 0, sizeof(msg));
 scanf("%s", msg);
 printf("%srn", msg);
 external_port = ATOI(msg, 10);
 printf("rnType a Internal Port Number : ");
 memset(msg, 0, sizeof(msg));
 scanf("%s", msg);
 printf("%srn", msg);
 internal_port = ATOI(msg, 10);
 if(strcmp(protocol,"tcp") || strcmp(protocol,"TCP"))
     tcps_port     = internal_port;
 else
     udps_port     = internal_port;
 close(sn2);
 // Try to Add Port Action
 getSIPR(Sip);
 sprintf(ipaddr, "%d.%d.%d.%d", Sip[0], Sip[1], Sip[2], Sip[3]);
 if ((ret = AddPortProcess(sn, protocol, external_port, ipaddr, internal_port, "W5500_uPnPGetway")) == 0)
     printf("AddPort Success!!rn");
 else
     printf("AddPort Error Code is %drn", ret);
}

在这里,我们需要外部输入端口映射的协议类型(TCP或UDP),以及外部端口号和内部端口号。输入完成后,选项5或选项6的端口号会替换为输入的内部端口号,然后通过AddPortProcess()函数执行添加端口映射处理。AddPortProcess()函数内容如下:

/**
* @brief This function processes the add port to IGD(Internet Gateway Device).
* @return 0: success, -2: Invalid UPnP Step, -1: reply packet timeout, 1: received xml parse error, other: UPnP error code
*/
signed short AddPortProcess(
SOCKET             sockfd,         /**< a socket number. */
const char        *protocol,       /**< a procotol name. "TCP" or "UDP" */
const unsigned int extertnal_port, /**< an external port number. */
const char        *internal_ip,    /**< an internal ip address. */
const unsigned int internal_port,  /**< an internal port number. */
const char        *description     /**< a description of this portforward. */
)
{
 short          len     = 0;
 long           endTime = 0;
 unsigned long  ipaddr;
 unsigned short port;
 // Check UPnP Step
 if (UPnP_Step < 2) return -2;
 // Make "Add Port" XML(SOAP)
 memset(content, '', CONT_BUFFER_SIZE);
 MakeSOAPAddControl(content, protocol, extertnal_port, internal_ip, internal_port, description);
 // Make HTTP POST Header
 memset(send_buffer, '', SEND_BUFFER_SIZE);
 len = strlen(content);
 MakePOSTHeader(send_buffer, len, ADD_PORT);
 strcat(send_buffer, content);
 //#ifdef UPNP_DEBUG
 printf("%srn", send_buffer);
 //#endif
 ipaddr = inet_addr((unsigned char *)descIP);
 ipaddr = swapl(ipaddr);
 port   = ATOI(descPORT, 10);
 // Connect to IGD(Internet Gateway Device)
 socket(sockfd, Sn_MR_TCP, PORT_UPNP, Sn_MR_ND); /*Open a port of the socket*/
 while (getSn_SR(sockfd) != SOCK_INIT);
 if (connect(sockfd, (unsigned char *)&ipaddr, port) == 0)
     printf("TCP Socket Error!!rn");
 // Send "Delete Port" Message
 while (getSn_SR(sockfd) != SOCK_ESTABLISHED);
 send(sockfd, (void *)send_buffer, strlen(send_buffer));
 // Receive Reply
 memset(recv_buffer, '', RECV_BUFFER_SIZE);
 delay_ms(500);
 endTime = my_time + 3;
 while (recv(sockfd, (void *)recv_buffer, RECV_BUFFER_SIZE) <= 0 && my_time < endTime); // Check Receive Buffer
 if (my_time >= endTime)
 {                                                                                      // Check Timeout
     close(sockfd);
     return -1;
 }
 // TCP Socket Close
 close(sockfd);
 //#ifdef UPNP_DEBUG
 printf("rnReceiveDatarn%srn", recv_buffer);
 //#endif
 // Parse Replied Message
 return parseAddPort(recv_buffer);
}

程序首先会通过MakeSOAPAddControl()函数组装请求报文中的XML部分,具体内容如下:

/**< SOAP header & tail */
const char soap_start[] =
   "
rn

";
const char soap_end[] =
   "
rn
";
/**< Delete Port Mapping */
const char DeletePortMapping_[] = "";
const char _DeletePortMapping[] = "";
/**< New Remote Host */
const char NewRemoteHost_[] = "";
const char _NewRemoteHost[] = "";
/**< New External Port */
const char NewExternalPort_[] = "";
const char _NewExternalPort[] = "";
/**< New Protocol */
const char NewProtocol_[] = "";
const char _NewProtocol[] = "";
/**< Add Port Mapping */
const char AddPortMapping_[] = "";
const char _AddPortMapping[] = "";
/**< New Internal Port */
const char NewInternalPort_[] = "";
const char _NewInternalPort[] = "";
/**< New Internal Client */
const char NewInternalClient_[] = "";
const char _NewInternalClient[] = "";
/**< New Enabled */
const char NewEnabled[]  = "1";
const char NewEnabled_[] = "";
const char _NewEnabled[] = "";
/**< New Port Mapping Description */
const char NewPortMappingDescription_[] = "";
const char _NewPortMappingDescription[] = "";
/**< New Lease Duration */
const char NewLeaseDuration[]  = "0";
const char NewLeaseDuration_[] = "";
const char _NewLeaseDuration[] = "";
/**
* @brief   This function makes the Add Port Control message in SOAP.
* @param   dest:Target string pointer
* @param   protocol:Protocol type
* @param   extertnal_port:External port
* @param   internal_ip:Internal IP address
* @param   internal_port:Internal port
* @param   description:Description
* @return  none
*/
void MakeSOAPAddControl(char *dest, const char *protocol, const unsigned int extertnal_port, const char * internal_ip, const unsigned int internal_port, const char *description)
{
   char local_port[6] = {''};
   strcat(dest, soap_start);
   strcat(dest, AddPortMapping_);
   strcat(dest, NewRemoteHost_);
   strcat(dest, _NewRemoteHost);
   strcat(dest, NewExternalPort_);
   sprintf(local_port, "%d", extertnal_port);
   strcat(dest, local_port);
   strcat(dest, _NewExternalPort);
   strcat(dest, NewProtocol_);
   strcat(dest, protocol);
   strcat(dest, _NewProtocol);
   strcat(dest, NewInternalPort_);
   sprintf(local_port, "%d", internal_port);
   strcat(dest, local_port);
   strcat(dest, _NewInternalPort);
   strcat(dest, NewInternalClient_);
   strcat(dest, internal_ip);
   strcat(dest, _NewInternalClient);
   strcat(dest, NewEnabled);
   strcat(dest, NewPortMappingDescription_);
   strcat(dest, description);
   strcat(dest, _NewPortMappingDescription);
   strcat(dest, NewLeaseDuration);
   strcat(dest, _AddPortMapping);
   strcat(dest, soap_end);
}

然后通过MakePOSTHeader()函数制作HTTP头部内容,具体内容如下:

  /**
 * @brief   This function makes the HTTP POST Header.
 * @param   dest:Target string pointer
 * @param   content_length: content length
 * @param   action: action type
 * @return  none
 */
 void MakePOSTHeader(char *dest, int content_length, int action)
 {
     char local_length[6] = {''}, local_port[6] = {''};
     sprintf(local_length, "%d", content_length);
     strcat(dest, "POST ");
     strcat(dest, controlURL);
     strcat(dest, " HTTP/1.1rn");
     strcat(dest, "Content-Type: text/xml; charset="utf-8"rn");
     strcat(dest, "SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#");
     switch (action)
     {
     case DELETE_PORT:
         strcat(dest, "DeletePortMapping"");
         break;
     case ADD_PORT:
         strcat(dest, "AddPortMapping"");
         break;
     }
     strcat(dest, "rnUser-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)rn");
     strcat(dest, "Host: ");
     strcat(dest, descIP);
     sprintf(local_port, ":%s", descPORT);
     strcat(dest, local_port);
     strcat(dest, "rnContent-Length: ");
     strcat(dest, local_length);
     strcat(dest, "rnConnection: Keep-AlivernCache-Control: no-cachernPragma: no-cachernrn");
 }

最后则是发送请求,然后通过parseAddPort()函数解析响应内容判断是否添加端口映射成功。

signed short parseAddPort(
 const char *xml /**< string for parse */
)
{
 parseHTTP(xml);
 if (strstr(xml, "u:AddPortMappingResponse xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1"") == NULL)
 {
     return parseError(xml);
 }
 return 0;
}

步骤8:删除一个UPnP端口映射表

if (choice[0] == '8')
{
 bTreat = SET;
 printf("rnType a Protocol(TCP/UDP) : ");
 memset(msg, 0, sizeof(msg));
 scanf("%s", msg);
 printf("%srn", msg);
 //GetInputString(msg);
 strncpy(protocol, msg, 3);
 protocol[3] = '';
 printf("rnType a External Port Number : ");
 //   TCP_LISTEN_PORT=num;
 //   UDP_LISTEN_PORT=num;
 //   printf("%drn",TCP_LISTEN_PORT);
 memset(msg, 0, sizeof(msg));
 scanf("%s", msg);
 printf("%srn", msg);
 external_port = ATOI(msg, 10);
 // Try to Delete Port Action
 if ((ret = DeletePortProcess(sn, protocol, external_port)) == 0)
     printf("DeletePort Success!!rn");
 else
     printf("DeletePort Error Code is %drn", ret);
}
/* OTHERS CHOICE*/
if (bTreat == RESET)
{
 printf(" wrong choice  rn");
}

在这里,我们需要外部输入删除端口映射的协议类型(TCP或UDP),以及外部端口号。输入完成后,通过DeletePortProcess()函数执行添加端口映射处理。DeletePortProcess()函数内容如下:

/**
* @brief This function processes the delete port to IGD(Internet Gateway Device).
* @return 0: success, -2: Invalid UPnP Step, -1: reply packet timeout, 1: received xml parse error, other: UPnP error code
*/
signed short DeletePortProcess(
 SOCKET             sockfd,        /**< a socket number. */
 const char        *protocol,      /**< a procotol name. "TCP" or "UDP" */
 const unsigned int extertnal_port /**< an external port number. */
)
{
 short          len     = 0;
 long           endTime = 0;
 unsigned long  ipaddr;
 unsigned short port;
 // Check UPnP Step
 if (UPnP_Step < 2) return -2;
 // Make "Delete Port" XML(SOAP)
 memset(content, '', CONT_BUFFER_SIZE);
 MakeSOAPDeleteControl(content, protocol, extertnal_port);
 // Make HTTP POST Header
 memset(send_buffer, '', SEND_BUFFER_SIZE);
 len = strlen(content);
 MakePOSTHeader(send_buffer, len, DELETE_PORT);
 strcat(send_buffer, content);
 //#ifdef UPNP_DEBUG
 printf("%srn", send_buffer);
 //#endif
 ipaddr = inet_addr((unsigned char *)descIP);
 ipaddr = swapl(ipaddr);
 port   = ATOI(descPORT, 10);
 // Connect to IGD(Internet Gateway Device)
 close(sockfd);
 socket(sockfd, Sn_MR_TCP, PORT_UPNP, Sn_MR_ND); /*Open a port of the socket*/
 while (getSn_SR(sockfd) != SOCK_INIT);
 if (connect(sockfd, (unsigned char *)&ipaddr, port) == 0)
     printf("TCP Socket Error!!rn");
 // Send "Delete Port" Message
 while (getSn_SR(sockfd) != SOCK_ESTABLISHED);
 send(sockfd, (void *)send_buffer, strlen(send_buffer));
 // Receive Reply
 memset(recv_buffer, '', RECV_BUFFER_SIZE);
 delay_ms(500);
 endTime = my_time + 3;
 while (recv(sockfd, (void *)recv_buffer, RECV_BUFFER_SIZE) <= 0 && my_time < endTime); // Check Receive Buffer 
 if (my_time >= endTime)
 {                                                                                      // Check Timeout
     close(sockfd);
     return -1;
 }
 // TCP Socket Close
 close(sockfd);
 //#ifdef UPNP_DEBUG
 printf("rnReceiveDatarn%srn", recv_buffer);
 //#endif
 // Parse Replied Message
 return parseDeletePort(recv_buffer);
}

首先会通过MakeSOAPDeleteControl()函数组装请求报文中的XML部分,具体内容如下:

/**
* @brief   This function makes the Delete Port Control message in SOAP.
* @param   dest:Target string pointer
* @param   protocol:Protocol type
* @param   extertnal_port:External port
* @return  none
*/
void MakeSOAPDeleteControl(char *dest, const char *protocol, const unsigned int extertnal_port)
{
    char local_port[6] = {''};
    strcat(dest, soap_start);
    strcat(dest, DeletePortMapping_);
    strcat(dest, NewRemoteHost_);
    strcat(dest, _NewRemoteHost);
    strcat(dest, NewExternalPort_);
    sprintf(local_port, "%d", extertnal_port);
    strcat(dest, local_port);
    strcat(dest, _NewExternalPort);
    strcat(dest, NewProtocol_);
    strcat(dest, protocol);
    strcat(dest, _NewProtocol);
    strcat(dest, _DeletePortMapping);
    strcat(dest, soap_end);
}

然后通过MakePOSTHeader()函数制作HTTP头部内容,具体内容如下:

 /**
* @brief   This function makes the HTTP POST Header.
* @param   dest:Target string pointer
* @param   content_length: content length
* @param   action: action type
* @return  none
*/
void MakePOSTHeader(char *dest, int content_length, int action)
{
   char local_length[6] = {''}, local_port[6] = {''};
   sprintf(local_length, "%d", content_length);
   strcat(dest, "POST ");
   strcat(dest, controlURL);
   strcat(dest, " HTTP/1.1rn");
   strcat(dest, "Content-Type: text/xml; charset="utf-8"rn");
   strcat(dest, "SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#");
   switch (action)
   {
   case DELETE_PORT:
       strcat(dest, "DeletePortMapping"");
       break;
   case ADD_PORT:
       strcat(dest, "AddPortMapping"");
       break;
   }
   strcat(dest, "rnUser-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)rn");
   strcat(dest, "Host: ");
   strcat(dest, descIP);
   sprintf(local_port, ":%s", descPORT);
   strcat(dest, local_port);
   strcat(dest, "rnContent-Length: ");
   strcat(dest, local_length);
   strcat(dest, "rnConnection: Keep-AlivernCache-Control: no-cachernPragma: no-cachernrn");
}

最后则是发送请求,然后通过parseDeletePort()函数解析响应内容判断是否添加端口映射成功。

signed short parseDeletePort(
 const char *xml /**< string for parse */
)
{
 parseHTTP(xml);
 if (strstr(xml, "u:DeletePortMappingResponse xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1"") == NULL)
 {
     return parseError(xml);
 }
 return 0;
}

7运行结果

烧录例程运行后,首先进行了PHY链路检测,然后是通过DHCP获取网络地址并打印网络地址信息:

wKgZO2iBk_qAJu0hAACGbFXSs4s753.png

接下来是搜索IGD设备,搜索成功后会进行获取设备描述以及设置订阅IGD事件,全部成功后则进入主菜单。

wKgZPGiBk_qAR8NXAAB7KK65PqM552.png

接着,我们输入7,添加一个TCP协议的端口映射,外部端口为12345,内部端口为8000。

wKgZPGiBlUGAJUKXAAB_qiS29yE458.png

打开UPnP Wizard软件,点击刷新后可以看到我们添加的端口映射表。(UPnP Wizard下载链接:https://upnp-wizard.en.softonic.com/)

wKgZPGiBk_qAPl1rAABLZ3dYYI0094.png

然后我们输入5,打开TCP回环测试程序。

wKgZO2iBk_qAPyybAAB2Yd2UAUQ634.png

随后,我们打开一个网络调试助手,例如SocketTester,选择为TCP Client模式,服务器地址为外部IP地址也就是192.168.1.135,端口号为外部端口号12345,点击”Connect”连接后,可以看到成功连接到内部的W55MH32上了。UDP也是同样进行操作,这里不再演示。

wKgZPGiBk_uAWsuuAABgCNp5Vw4452.png

接着我们输入Q退出回环测试程序,然后输入8,将之前添加的TCP协议的12345外部端口删除。在UPnP Wizard上点击刷新,可以看到已经成功删除,再次执行回环测试程序,已经无法连接上内部的W55MH32上。

wKgZPGiBk_qAHCnnAACLZa5NCuc107.pngwKgZO2iBk_qATGsqAADLCfGoIX0170.pngwKgZO2iBk_qAdqobAAAnyGquMak336.pngwKgZO2iBk_uAH-J3AACQC9YpHyc941.png

8总结

本文讲解了如何在 W55MH32芯片上实现 UPnP协议的端口转发功能,通过实战例程详细展示了从设备搜索、获取设备描述、订阅事件到添加和删除端口映射的完整流程,包括各步骤涉及的协议报文、函数实现和具体操作。文章还对 UPnP协议的简介、特点、应用场景进行了分析,帮助读者理解其在网络设备互联互通中的实际应用价值。

下一篇文章将聚焦 TFTP协议,解析其核心原理及在文件传输中的应用,同时讲解如何在W55MH32上实现 TFTP功能,敬请期待!

WIZnet是一家无晶圆厂半导体公司,成立于 1998年。产品包括互联网处理器 iMCU?,它采用 TOE(TCP/IP卸载引擎)技术,基于独特的专利全硬连线 TCP/IP。iMCU?面向各种应用中的嵌入式互联网设备。

WIZnet在全球拥有 70多家分销商,在香港、韩国、美国设有办事处,提供技术支持和产品营销。

香港办事处管理的区域包括:澳大利亚、印度、土耳其、亚洲(韩国和日本除外)。

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 以太网
    +关注

    关注

    41

    文章

    5706

    浏览量

    176471
  • 端口
    +关注

    关注

    4

    文章

    1048

    浏览量

    33029
  • UPnP
    +关注

    关注

    0

    文章

    7

    浏览量

    8517
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    第二十六章 W55MH32?上位机搜索和配置示例

    本文讲解了如何在 W55MH32?芯片上实现上位机搜索和配置功能,通过实战例程展示了使用开源上位机配置工具 SmartConfigTool?搜索局域网中的 W55MH32?并进行网络地址配置的过程
    的头像 发表于 07-24 16:13 ?146次阅读
    第二十六章 <b class='flag-5'>W55MH32</b>?上位机搜索和配置<b class='flag-5'>示例</b>

    第二十三章 W55MH32 MQTT_OneNET示例

    本文讲解了如何在 W55MH32?芯片上实现 MQTT?协议并连接 OneNET?平台,通过实战例程展示了从准备工作、连接配置到消息订阅、发布及接收处理的完整过程。文章详细介绍了 MQTT?协议
    的头像 发表于 07-24 14:59 ?174次阅读
    第二<b class='flag-5'>十三章</b> <b class='flag-5'>W55MH32</b> MQTT_OneNET<b class='flag-5'>示例</b>

    第十八章 W55MH32 FTP_Server示例

    本文讲解了如何在 W55MH32?芯片上实现 FTP?协议的服务器模式,通过实战例程展示了使用 W55MH32?作为 FTP?服务器与 PC?端进行文件传输、目录操作等功能的过程,涵盖获取网络配置
    的头像 发表于 07-24 11:55 ?102次阅读
    <b class='flag-5'>第十</b>八章 <b class='flag-5'>W55MH32</b> FTP_Server<b class='flag-5'>示例</b>

    第十七章 W55MH32 ARP示例

    文讲解了如何在 W55MH32?芯片上通过 MAC RAW?模式实现 ARP?协议,将 IP?地址解析为 MAC?地址,通过实战例程展示了从发送 ARP?请求到接收并处理响应的完整过程。文章详细介绍
    的头像 发表于 07-24 11:49 ?197次阅读
    <b class='flag-5'>第十</b>七章 <b class='flag-5'>W55MH32</b> ARP<b class='flag-5'>示例</b>

    第十六章 W55MH32 PING示例

    本文讲解了如何在 W55MH32?芯片上通过 IPRAW?模式实现 ICMP?协议中的 PING?命令,以进行网络连通性测试,通过实战例程展示了从发送 PING?请求、接收并解析回复到统计结果的完整
    的头像 发表于 07-24 11:41 ?101次阅读
    <b class='flag-5'>第十</b>六章 <b class='flag-5'>W55MH32</b> PING<b class='flag-5'>示例</b>

    第十五章 W55MH32 SNMP示例

    本文讲解了如何在 W55MH32?芯片上实现 SNMP?功能,通过实战例程展示了使用 MIB Browser?管理 W55MH32?的具体过程,涵盖在 MIB Browser?中创建分支、添加叶子
    的头像 发表于 07-24 10:43 ?204次阅读
    <b class='flag-5'>第十</b>五章 <b class='flag-5'>W55MH32</b> SNMP<b class='flag-5'>示例</b>

    第十四章 W55MH32 TFTP示例

    本文讲解了如何在 W55MH32?芯片上实现 TFTP?协议,通过实战例程详细展示了使用 TFTP?客户端模式从服务器获取文本文件的过程,涵盖 TFTP?初始化、发送读请求、运行协议并处理结果等核心
    的头像 发表于 07-24 10:37 ?181次阅读
    <b class='flag-5'>第十</b>四章 <b class='flag-5'>W55MH32</b> TFTP<b class='flag-5'>示例</b>

    第十二章 W55MH32 NetBIOS示例

    本文讲解了如何在 W55MH32?芯片上实现 NetBIOS?功能,通过实战例程展示了利用 NetBIOS?进行名称 PING?测试的具体过程,包括 NetBIOS?功能的调用、请求处理、名称解析
    的头像 发表于 07-24 09:58 ?175次阅读
    <b class='flag-5'>第十</b>二章 <b class='flag-5'>W55MH32</b> NetBIOS<b class='flag-5'>示例</b>

    第十一章 W55MH32 SMTP示例

    本文讲解了如何在 W55MH32?芯片上实现 SMTP?协议,通过实例详细展示了在该芯片上使用 SMTP?协议发送电子邮件的实现流程,包括 SMTP?发送内容初始化、使用 DNS?协议解析 SMTP
    的头像 发表于 07-24 09:49 ?201次阅读
    <b class='flag-5'>第十</b>一章 <b class='flag-5'>W55MH32</b> SMTP<b class='flag-5'>示例</b>

    第十W55MH32 SNTP示例

    本文讲解了如何在W55MH32芯片上实现SNTP授时功能,通过实例详细展示了从SNTP服务器同步时间的实现流程,包括时间请求、响应解析和本地时间校准等核心步骤。文章还对SNTP的应用场景进行了分析,帮助读者理解其在时间同步中的实际应用价值。
    的头像 发表于 07-24 09:43 ?307次阅读
    <b class='flag-5'>第十</b>章 <b class='flag-5'>W55MH32</b> SNTP<b class='flag-5'>示例</b>

    第九章 W55MH32 HTTP Server示例

    本文介绍了在 W55MH32?芯片上实现 HTTP Server?功能,并通过浏览器修改其网络地址信息的方法。阐述了 HTTP?协议的概念、特点、应用场景、工作流程、请求方法、响应内容,以及 Web?页面构成和交互方式。展示了在W55MH32上实现的过程。
    的头像 发表于 07-24 09:35 ?158次阅读
    第九章 <b class='flag-5'>W55MH32</b> HTTP Server<b class='flag-5'>示例</b>

    第五章 W55MH32 UDP示例

    本文介绍了在 W55MH32?芯片上实现 UDP?通信及数据回环测试的方法。阐述了 UDP?协议的概念、特点、应用场景、报文传输流程和报文结构,展示了实现过程,借助网络调试工具完成测试。
    的头像 发表于 07-24 09:13 ?125次阅读
    第五章 <b class='flag-5'>W55MH32</b> UDP<b class='flag-5'>示例</b>

    三章 W55MH32 TCP Client示例

    本文介绍在 W55MH32?芯片上实现 TCP?客户端模式进行数据回环测试的方法。阐述 TCP?协议概念、特点、与 UDP?区别、应用场景及相关机制。展示实现过程,包括开启 Keepalive?功能,在主循环运行测试程序。烧录例程后进行 PHY?链路检测、获取网络地址,再借助网络调试工具测试。
    的头像 发表于 07-24 09:06 ?204次阅读
    第<b class='flag-5'>三章</b> <b class='flag-5'>W55MH32</b> TCP Client<b class='flag-5'>示例</b>

    第二章 W55MH32 DHCP示例

    本文介绍 DHCP?协议,包括其在 IP?网络自动分配参数的功能、便捷配置等特点、工作原理、报文格式和应用场景。通过 W55MH32?实战例程展示动态获取网络地址信息过程,含注册定时器中断、启用模式和获取信息等步骤,烧录后可完成检测与信息打印,PC?端能 PING?通设备。
    的头像 发表于 07-24 09:02 ?185次阅读
    第二章 <b class='flag-5'>W55MH32</b> DHCP<b class='flag-5'>示例</b>

    WIZnet W55MH32以太网单片机开发教程 第十一章 通用定时器(上篇)

    本章介绍了W55MH32的通用定时器TIM2~TIM5,其由 16 位计数器等构成,具输入捕获等功能,有多种计数模式及时钟选择。对例程进行了讲解并下载验证,TIM9~14功能类似,详见《W55MH32参考手册》。
    的头像 发表于 05-28 10:12 ?430次阅读
    WIZnet <b class='flag-5'>W55MH32</b>以太网单片机开发教程 <b class='flag-5'>第十</b>一章 通用定时器(上篇)