7. HTTP-Client例程讲解#

1. 环境准备#

首先,确保你的CanMV开发板已经通过网口与路由器或交换机相连,并且路由器能够正常工作,具备访问互联网的能力。这是进行HTTP请求的基础环境设置。

2. 例程详解#

下面的Python例程展示了如何在CanMV开发板上实现一个简单的HTTP客户端,用于向指定的服务器(本例中为百度)发送HTTP GET请求,并接收响应内容。

2.1 导入必要的模块#

import network  
import socket

这里导入了networksocket两个模块。network模块用于管理网络接口,而socket模块则提供了网络通信的底层接口。

2.2 定义主函数#

def main(use_stream=True):  
    # ...(后续代码)

定义了一个名为main的函数,它接受一个名为use_stream的参数,默认为True。这个参数用于控制是否使用流式接口来读取响应数据。

2.3 配置网络接口#

def network_use_wlan(is_wlan=True):
    if is_wlan:
        sta=network.WLAN(0)
        sta.connect("Canaan","Canaan314")
        print(sta.status())
        while sta.ifconfig()[0] == '0.0.0.0':
            os.exitpoint()
        print(sta.ifconfig())
        ip = sta.ifconfig()[0]
        return ip
    else:
        a=network.LAN()
        if not a.active():
            raise RuntimeError("LAN interface is not active.")
        a.ifconfig("dhcp")
        print(a.ifconfig())
        ip = a.ifconfig()[0]
        return ip

这段代码根据输入参数来配置网络接口。主要流程如下:

  1. WLAN模式

    • 如果 is_wlan 参数为 True,则程序配置无线网络接口(WLAN)。

    • 创建 WLAN 接口实例并尝试连接到指定的 Wi-Fi 网络(SSID 为 “Canaan”,密码为 “Canaan314”)。

    • 打印 WLAN 接口的连接状态,并在获得有效 IP 地址之前循环等待。

    • 成功连接后,打印网络配置并返回获取的 IP 地址。

  2. LAN模式

    • 如果 is_wlan 参数为 False,则程序配置有线网络接口(LAN)。

    • 获取 LAN 接口实例并检查其是否已激活。

    • 如果接口未激活,抛出 RuntimeError 异常,提示接口未激活。

    • 将 LAN 接口配置为 DHCP 模式,自动从路由器获取 IP 地址。

    • 打印网络配置并返回获取的 IP 地址。

2.4 创建并配置socket#

# 创建socket对象  
s = socket.socket()  
# 尝试获取目标地址和端口号  
ai = []  
for attempt in range(0, 3):  
    try:  
        ai = socket.getaddrinfo("www.baidu.com", 80)  
        break  
    except:  
        print("getaddrinfo again")  
  
# 检查是否成功获取地址信息  
if ai == []:  
    print("连接错误")  
    s.close()  
    return  
  
# 提取地址和端口号  
addr = ai[0][-1]  
print("连接地址:", addr)

这段代码首先创建了一个socket对象,然后尝试通过getaddrinfo函数获取目标服务器(百度)的地址和端口号信息。为了提高代码的健壮性,这里使用了重试机制,最多尝试3次。如果成功获取到地址信息,则提取出地址和端口号,并打印出来。

2.5 发送HTTP请求并接收响应#

# 连接到服务器  
s.connect(addr)  
  
if use_stream:  
    # 使用流式接口读取响应  
    s = s.makefile("rwb", 0)  
    s.write(b"GET /index.html HTTP/1.0\r\n\r\n")  
    print(s.read())  
else:  
    # 直接使用socket接口发送和接收数据  
    s.send(b"GET /index.html HTTP/1.0\r\n\r\n")  
    print(s.recv(4096))  
  
# 关闭socket  
s.close()

这部分代码首先连接到服务器,然后根据use_stream参数的值选择使用流式接口还是直接通过socket接口发送HTTP请求。如果use_streamTrue,则使用流式接口发送请求并读取整个响应;如果为False,则直接发送请求并接收一定长度的响应数据(本例中为4096字节)。最后,关闭socket连接以释放资源。

2.6 函数调用#

# 调用主函数,分别测试流式接口和非流式接口  
main(use_stream=True)  
main(use_stream=False)

最后,通过调用main函数并传入不同的use_stream参数值,可以分别测试流式接口和非流式接口的效果。这样可以帮助你更好地理解这两种方式在读取HTTP响应时的差异。

2.7 完整例程#

import network
import socket
import os,time

def network_use_wlan(is_wlan=True):
    if is_wlan:
        sta=network.WLAN(0)
        sta.connect("Canaan","Canaan314")
        print(sta.status())
        while sta.ifconfig()[0] == '0.0.0.0':
            os.exitpoint()
        print(sta.ifconfig())
        ip = sta.ifconfig()[0]
        return ip
    else:
        a=network.LAN()
        if not a.active():
            raise RuntimeError("LAN interface is not active.")
        a.ifconfig("dhcp")
        print(a.ifconfig())
        ip = a.ifconfig()[0]
        return ip

def main(use_stream=True):
  
    #获取lan接口
    network_use_wlan(True)
    #创建socket
    s = socket.socket()
    #获取地址及端口号 对应地址
    ai = []
      
    for attempt in range(0, 3):
        try:
            #获取地址及端口号 对应地址
            ai = socket.getaddrinfo("www.baidu.com", 80)
            break
        except:
            print("getaddrinfo again");
  
    if(ai == []):
        print("connet error")
        s.close()
        return

    print("Address infos:", ai)
    addr = ai[0][-1]
  
    print("Connect address:", addr)
    #连接
    s.connect(addr)

    if use_stream:
        # MicroPython socket objects support stream (aka file) interface
        # directly, but the line below is needed for CPython.
        s = s.makefile("rwb", 0)
        #发送http请求
        s.write(b"GET /index.html HTTP/1.0\r\n\r\n")
        #打印请求内容
        print(s.read())
    else:
        #发送http请求
        s.send(b"GET /index.html HTTP/1.0\r\n\r\n")
        #打印请求内容
        print(s.recv(4096))
        #print(s.read())
    #关闭socket
    s.close()


#main()
main(use_stream=True)
main(use_stream=False)

具体接口定义请参考 socketnetwork