衢州房产网:关于 k210 的 micropython 添加 ussl 模块,实现 https 接见支持的那些事。

admin 5个月前 (05-12) 科技 42 0

原由

事情已经已往快一周了吧,继上次修复 maixpy k210 的 esp8285 at 通讯后,突然遇到泽畔大大问,要不要做 ussl 的支持?

评估了一下各方的实现,想了一下自己也恰好在做网络层的优化和处置,况且 micropython 在 stm32 、 esp32 上的也有对应的实现,那就添加实现进去吧,选取了 mbedtls 版本的 ussl 模块,实现相关文件如下。

这里说一下 ussl 的事情机制。

首先确立在 micropython 的 network 架构下的 socket 模块,提供了要害的 steam->write 和 steam->read 基础接口,实际上就是继续一个抽象 steam 工具的接口。

因此 ussl 提供了 wrap_socket 用来提升 socket 的功效,从而支持 https 的接见。

我们看一下 micropython 的实例就知道了。

try:
    import usocket as _socket
except:
    import _socket
try:
    import ussl as ssl
except:
    import ssl

def main(use_stream=True):
    s = _socket.socket()

    ai = _socket.getaddrinfo("google.com", 443)
    print("Address infos:", ai)
    addr = ai[0][-1]

    print("Connect address:", addr)
    s.connect(addr)

    s = ssl.wrap_socket(s)
    print(s)

    if use_stream:
        # Both CPython and MicroPython SSLSocket objects support read() and
        # write() methods.
        s.write(b"GET / HTTP/1.0\r\n\r\n")
        print(s.read(4096))
    else:
        # MicroPython SSLSocket objects implement only stream interface, not
        # socket interface
        s.send(b"GET / HTTP/1.0\r\n\r\n")
        print(s.recv(4096))

    s.close()

main()

实现的最终效果如下,不外现在的实测效果距离商业使用,守旧来讲,另有很大的优化空间,主要在焦点函数和设置方面要改善性能。

  • esp32 的效果

  • k210 的效果

衢州房产网:关于 k210 的 micropython 添加 ussl 模块,实现 https 接见支持的那些事。 第1张

衢州房产网:关于 k210 的 micropython 添加 ussl 模块,实现 https 接见支持的那些事。 第2张

实现细节

MaixPy k210 接纳 components/micropython/CMakeLists.txt 来治理 micropython 的编译下令。

以是在不脱离主流的基础上,在 micropython-ulab 的设置后面继续添加如下设置。

    if(1 OR CONFIG_MICROPY_SSL_MBEDTLS)
        list(APPEND ADD_INCLUDE "${mpy_core_dir}/lib/mbedtls/include")
        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMBEDTLS_CONFIG_FILE='\"${mpy_port_dir}/src/mbedtls/include/mbedtls_config.h\"'")
        # message(${CMAKE_C_FLAGS})
        append_srcs_dir(ADD_SRCS "port/src/mbedtls")
        append_srcs_dir(ADD_SRCS "core/lib/mbedtls/library")
        list(REMOVE_ITEM ADD_SRCS "${mpy_core_dir}/lib/mbedtls/library/net_sockets.c")
    endif()

稍微注释一下

  • 将 mbedtls/include 和 mbedtls/library 添加到环境中,并清扫 net_sockets.c 的实现,问题下述。

衢州房产网:关于 k210 的 micropython 添加 ussl 模块,实现 https 接见支持的那些事。 第3张

  • 给 CMAKE_C_FLAGS 添加 -DMBEDTLS_CONFIG_FILE 自定义的 mbedtls 设置文件,从而屏障内置的 config.h 。(新鲜的是 add_definitions 不 work ,就直接用 set 了)
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif

以是现在把代码编译了进去,就完成了大部分的移植,是不是很简朴?

修改纪录在这里,可供参考。

固然,事情不会这么顺遂的,在没有举行专门设置的时刻,启动模块是可以的,现在最先实践提议一次 get https 网站的请求,测试 python code 如下:


wCli = MicroWebCli('https://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=13631786501')
# wCli = MicroWebCli('https://www.baifubao.com/callback?cmd=1059&callback=phone&phone=13631786501')
# wCli = MicroWebCli('https://github.com')
# wCli = MicroWebCli('https://ssl.logink.cn/')
# wCli = MicroWebCli('https://cn.bing.com/?FORM=Z9FD1')
# wCli = MicroWebCli('https://www.sojson.com')
# wCli = MicroWebCli('https://www.baidu.com')

while True:
    try:
        print('GET %s' % wCli.URL)
        wCli.OpenRequest()
        buf  = memoryview(bytearray(1024))
        resp = wCli.GetResponse()
        if resp.IsSuccess() :
          while not resp.IsClosed() :
            x = resp.ReadContentInto(buf)
            if x < len(buf) :
              buf = buf[:x]
            print(bytes(buf))
          print('GET success with "%s" content type' % resp.GetContentType())
        else :
          print('GET return %d code (%s)' % (resp.GetStatusCode(), resp.GetStatusMessage()))
    except Exception as E:
        print(E)
    time.sleep(2)

问题一: -0x0034 错误代码

Gather entropy_len bytes of entropy to seed state

mbedtls_ctr_drbg_seed returned -52 或者-0x0034

错误注释:

MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED        -0x0034  /**< The entropy source failed. */

缘故原由:

给mbedtls提供的熵源不够杂乱,应该用硬件随机数发生器。

解决:

mbedtls\config.h

#define MBEDTLS_ENTROPY_HARDWARE_ALT

解决方案可以参考

https://blog.csdn.net/liaofeifly/article/details/88899655

mbedtls_hardware_poll 实现可以参考 esp32 、stm32 的,如下是我厥后实践到 k210 的,这个函数只会在提议链接的时刻挪用。


#include <stdlib.h>
#include <stdio.h>
#include "rng.h"

#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif

#include "mphalport.h"

int os_get_random(unsigned char *buf, size_t len)
{
    int i, j;
    unsigned long tmp;
 
    for (i = 0; i < ((len + 3) & ~3) / 4; i++) {
        tmp = rng_get() + systick_current_millis();
 
        for (j = 0; j < 4; j++) {
            if ((i * 4 + j) < len) {
                buf[i * 4 + j] = (uint8_t)(tmp >> (j * 8));
            } else {
                break;
            }
        }
    }
 
    return 0;
}

int mbedtls_hardware_poll( void *data, unsigned char *output, size_t len, size_t *olen )
{
    int res = os_get_random(output, len);
    *olen = len;
    return 0;
}

// int mbedtls_hardware_poll(void *data, unsigned char *output, size_t len, size_t *olen) {
//     uint32_t val;
//     int n = 0;
//     *olen = len;
//     while (len--) {
//         if (!n) {
//             val = rng_get();
//             n = 4;
//         }
//         *output++ = val;
//         val >>= 8;
//         --n;
//     }
//     return 0;
// }

问题二: -0x7280 错误代码

错误类型是

#define MBEDTLS_ERR_SSL_CONN_EOF -0x7280 /**< The connection indicated an EOF. */

这个问题我看了良久,由于上来就给我当头一棒,任何 https 的接见都布星。

那就奇了怪了,然后我开了 debug 开关,开到品级 4 后。

    #ifdef MBEDTLS_DEBUG_C
    // Debug level (0-4)
    mbedtls_debug_set_threshold(4);
    #endif

发现 TM 有在流动数据,而且是在事情的,而且看数据发现是正常事情的。

衢州房产网:关于 k210 的 micropython 添加 ussl 模块,实现 https 接见支持的那些事。 第4张

衢州房产网:关于 k210 的 micropython 添加 ussl 模块,实现 https 接见支持的那些事。 第5张

那么开了 debug 和没有开 debug 的区别在那里呢?

衢州房产网:关于 k210 的 micropython 添加 ussl 模块,实现 https 接见支持的那些事。 第6张

可以想象的是 debug 一定会对程序执行发生一些细微的差距,最后通过几回 debug 的后定位到是这个函数的延时保障了程序的执行。

衢州房产网:关于 k210 的 micropython 添加 ussl 模块,实现 https 接见支持的那些事。 第7张

看起来是不是很新鲜?为什么呢?若是在这里简朴的延时就会发生下述的效果。

衢州房产网:关于 k210 的 micropython 添加 ussl 模块,实现 https 接见支持的那些事。 第8张

也就是请求时好时坏,若是知道是需要延时的话,那么又该延时若干呢?

此时交给名侦探登场,真相只有一个!

首先函数来自于 f_send 操作,这个一定是个回调,然后定位它。


void mbedtls_ssl_set_bio( mbedtls_ssl_context *ssl,
        void *p_bio,
        mbedtls_ssl_send_t *f_send,
        mbedtls_ssl_recv_t *f_recv,
        mbedtls_ssl_recv_timeout_t *f_recv_timeout )
{
    ssl->p_bio          = p_bio;
    ssl->f_send         = f_send;
    ssl->f_recv         = f_recv;
    ssl->f_recv_timeout = f_recv_timeout;
}

说明来自上层,那么继续,定位到 /home/junhuanchen/MaixPy/components/micropython/core/extmod/modussl_mbedtls.c 。

    mbedtls_ssl_set_bio(&o->ssl, &o->sock, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL);

说明回调的是 _mbedtls_ssl_send 函数,如下。


STATIC int _mbedtls_ssl_send(void *ctx, const byte *buf, size_t len) {
    mp_obj_t sock = *(mp_obj_t*)ctx;

    const mp_stream_p_t *sock_stream = mp_get_stream(sock);
    int err;
    mp_uint_t out_sz = sock_stream->write(sock, buf, len, &err);
    if (out_sz == MP_STREAM_ERROR) {
        if (mp_is_nonblocking_error(err)) {
            return MBEDTLS_ERR_SSL_WANT_WRITE;
        }
        return -err;
    } else {
        return out_sz;
    }
}

经由测试发现,延时不应该上在 sock_stream->write 之前,而是之后,那么这说明什么问题呢?

若是要解决问题,是可以在这里添加延时解决问题,然则这里是问题的源头吗?显然不是。

判断有二

  • esp32 为什么没有这个问题?
  • 这个模块的位置在 micropython core 系统下,说明有大量的实例支持它们的逻辑准确性。

那么说明问题并不是这个地方导致的,在这个 micropython 的系统里,这时刻只能说明一个问题,是网卡的 sock_stream->write 请求过快返回导致的问题。

而我在用的是 ESP8285 的 AT 网卡,这就可以联想到 esp_send 的事情机制不一定相符尺度 socket 事情时序。

为什么呢?

由于 AT 的请求只需要将数据发送已往即可完成传输,但传输准确与否请求这端不直接参与,这与其他芯片的事情到链路层发送数据的机制差别,以是就会提前返回。

若是我的假设是准确的,那么我应该把问题定位到这里 components/micropython/port/src/standard_lib/network/esp8285/modesp8285.c 之中的 esp8285_socket_send 函数。


STATIC mp_uint_t esp8285_socket_send(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno) {

	if((mp_obj_type_t*)&mod_network_nic_type_esp8285 != mp_obj_get_type(MP_OBJ_TO_PTR(socket->nic)))
	{
		*_errno = MP_EPIPE;
		return MP_STREAM_ERROR;
	}
	nic_obj_t* self = MP_OBJ_TO_PTR(socket->nic);
    if(socket->peer_closed)
    {
        *_errno = MP_ENOTCONN;
        return MP_STREAM_ERROR;
    }
    Buffer_Clear(&self->esp8285.buffer);//clear receive buffer
    socket->first_read_after_write = true;
	if(0 == esp_send(&self->esp8285,(const char*)buf,len, (uint32_t)(socket->timeout*1000) ) )
	{
		*_errno = MP_EPIPE;
		return MP_STREAM_ERROR;
	}
    // printk("%s len %d\r\n", __func__, len);
    mp_hal_delay_us(len * 50); // maybe 50 us time required to send per byte
    // vTaskDelay(len / portTICK_PERIOD_MS);
    return len;
}

在这里我做了一个假设性的 timing 测试,假设为了修复它与其他芯片同步的事情时序,那么我应该在发送数据后举行一段时间的延时,但这个延时是多久呢?

我现在通讯在用的波特率都是 921600 ,在这个假设可行的情况下,我假定每个字节发送到对端需要的时间为 100 us 即 mp_hal_delay_us(len * 50); ,以此举行测试。

衢州房产网:关于 k210 的 micropython 添加 ussl 模块,实现 https 接见支持的那些事。 第9张

结论是实测 100 us 恢复正常事情,示意已经修复乐成,那么就竣事了吗?

还没,我们应该还要继续确定,真正预期的延时应该是若干?

接着二分法到 50 us 也乐成。

继续二分法到 25 us 也乐成。

继续二分法到 10 us 却不乐成。// 虚伪二分

那么结论也有个也许了,考虑到 921600 的速率过快,我原本思索要么就 25 us 最优方案。

但厥后发现,每次请求的数据并不会应该这个值而有所改善性能,反而可能会存在小概率请求失败,那既然没影响,应该守旧设置到 50 us 对照合理。

修改纪录在此

此时修改的位置异常合理,一方面不损坏 esp32 spi 那端的网卡,另一方面也不损坏 micropython core 的代码,从而对照优雅的解决问题。

最后做个总结

实测 https 的网站都有如下,不外 github.com 的 hostname 经常获取不到,dns 炸裂

wCli = MicroWebCli('https://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=13631786501')
wCli = MicroWebCli('https://www.baifubao.com/callback?cmd=1059&callback=phone&phone=13631786501')
wCli = MicroWebCli('https://github.com')
wCli = MicroWebCli('https://ssl.logink.cn/')
wCli = MicroWebCli('https://cn.bing.com/?FORM=Z9FD1')
wCli = MicroWebCli('https://www.sojson.com')
wCli = MicroWebCli('https://www.baidu.com')

衢州房产网:关于 k210 的 micropython 添加 ussl 模块,实现 https 接见支持的那些事。 第10张

另外 HTTPS 的接见速率没有想象的快,从确立链接到收发数据就需要差不多 20s,相比 HTTP 的 10 秒一次请求,这中心有很大的优化空间。

简朴判断跟加密解密的软实现函数的效率有关,也可能跟目的网站的响应速率以及对应的 TLS 传输协议有关,可以进一步优化 mbedtls 的设置文件。

需要实测真实用户的 https 的使用环境才气进一步优化。

2020年5月11日 junhuanchen 留

,

sunbet

Sunbet www.hbhaka.cn立足亚洲,展望未来,期待在2019年,更好地为Sunbet代理、会员服务。无广告无弹窗免vip的免费小说每天更新最及时。

Allbet声明:该文看法仅代表作者自己,与本平台无关。转载请注明:衢州房产网:关于 k210 的 micropython 添加 ussl 模块,实现 https 接见支持的那些事。

网友评论

  • (*)

最新评论

文章归档

站点信息

  • 文章总数:771
  • 页面总数:0
  • 分类总数:8
  • 标签总数:1298
  • 评论总数:352
  • 浏览总数:21050