本篇目标:在之前能ping通pc机的工程基础上搭建web服务器,借鉴官方web服务器的程序与网页,能够用pc机浏览器访问web服务器,并返回设置的网页

材料准备:

  • 基础工程:修改后能ping通pc机的工程(STM32官方移植lwip修改代码)
  • 搭建工程:最终搭建好的web服务器工程(STM32搭建web服务器工程)(git仓库地址)
  • 调试工具:用来调试tcp连接下的数据接收(网络调试助手)
  • 测试浏览器:这里使用的是Chrome谷歌浏览器

ps:通过修改官方搭建web服务器的代码,来了解搭建的过程,其中暂时去掉了ssi和cgi的程序,仅仅实现网页数据的返回和网页的跳转,并将官方的代码简化到相对最简,以便以后的学习之用


浏览器请求指令探索

要搭建服务器,首先肯定要先了解远程客户端是怎么访问服务器的,这里pc机的浏览器则作为客户端:

  1. 打开浏览器(谷歌浏览器测试),输入服务器ip;
  2. 浏览器发送请求命令给服务器;
  3. 服务器接收到指令后,通过程序来解析指令,找到对应应该返回的网页;
  4. 服务器发送网页代码给浏览器;
  5. 浏览器显示网页;

接下来再用搭建虚拟服务器的方法,来模拟一下上面的过程:

  • 打开网络调试助手,切换到网络服务器,在服务器操作端口输入80,点击创建,如图;这样我们就创建了一个虚拟的服务器,这个服务器的ip就是pc机的本地ip

  • 查看确认一下本地ip地址,可以在网络连接里面查看,也可以在cmd输命令查看,这里的ip地址为192.168.6.104,如图:

  • 打开浏览器(谷歌浏览器测试),输入刚才确认的本地ip地址,这里输入192.168.6.104:

  • 返回去看看刚才搭建的服务器有什么变化,会发现有接收到的数据,只要重点观察第一行的数据“GET / HTTP/1.1”,这个字符串将会被服务器解析,然后将网页代码返回回去:

  • 找到一个官方程序有一个fs文件夹,里面有已经做好的网页,打开网页index.html,右击-查看源代码,然后全选复制下来,在网络调试助手的发送区粘贴,并点击发送,如图:

  • 这时,会发现浏览器已经显示了一张网页,但是好像又有点不全,因为图片没有显示,为什么呢?返回网络调试助手,发现接收区又有好多请求,看字面意思,好像就是图片的请求,然而服务器没有返回图片数据,所以图片无法显示

  • 这时候,将所有的浏览器请求列出来比较一下:
    “GET / HTTP/1.1”
    “GET /STM32F4x7_files/ST.gif HTTP/1.1”
    “GET /inchtml-pages-stm32_connectivity_files/pixel.gif HTTP/1.1”
    “GET /STM32F4x7_files/stm32.jpg HTTP/1.1”
    发现请求中 / 后面一部分的内容不相同,所以服务器只需要解析这一部分的字符串内容,来返回对应的网页数据即可


搭建web服务器

现在创建一个新的c文件,取名为 http_server.c ,接下来写几个函数来建立web服务器,抽重要的函数进行总结一下:

  • web服务器初始化函数 Http_Server_Init():
void Http_Server_Init(void)
{struct tcp_pcb *http_server_pcb;/* 为web服务器分配一个tcp_pcb结构体 */http_server_pcb = tcp_new();/* 绑定本地端号和IP地址 */tcp_bind(http_server_pcb, IP_ADDR_ANY, 80);/* 监听之前创建的结构体http_server_pcb */http_server_pcb = tcp_listen(http_server_pcb);/* 初始化结构体接收回调函数 */tcp_accept(http_server_pcb, http_server_accept);
}

小结:上面函数主要就是为搭建web服务器做准备,包括申请网络结构体、设置80端口号、监听数据、设置接收数据回调函数;

  • 接收数据回调函数 tcp_server_accept() :
static err_t http_server_accept(void *arg, struct tcp_pcb *pcb, err_t err)
{struct http_state *hs;/* 分配内存空间 */hs = (struct http_state *)mem_malloc(sizeof(struct http_state));if (hs != NULL){memset(hs, 0, sizeof(struct http_state));}/* 确认监听和连接 */tcp_arg(pcb, hs);/* 配置接收回调函数 */tcp_recv(pcb, http_server_recv);/* 配置轮询回调函数 */tcp_poll(pcb, http_server_poll, 4);/* 配置发送回调函数 */tcp_sent(pcb, http_sent);return ERR_OK;
}

小结:函数中主要配置一些回调函数,比如接收,轮询,发送;

  • 接收数据处理函数 http_server_recv() :
static err_t http_server_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *http_recv_pbuf, err_t err)
{err_t parsed = ERR_ABRT;struct http_state *hs = (struct http_state *)arg;/* 告诉tcp已经接收到数据 */tcp_recved(pcb, http_recv_pbuf->tot_len);if (hs->handle == NULL){/* 解析接收到的浏览器请求数据 */parsed = http_parse_request(&http_recv_pbuf, hs, pcb);}/* 清空请求字符串 */if (parsed != ERR_INPROGRESS) {     if (hs->req != NULL) {pbuf_free(hs->req);hs->req = NULL;}}if (parsed == ERR_OK){/* 发送网页数据 */http_send_data(pcb, hs);}else if (parsed == ERR_ARG){/* 关闭连接 */close_conn(pcb, hs);}return ERR_OK;
}

小结:函数主要工作将接收到的数据放入 http_parse_request() 函数进行解析,然后把网页数据发送出去;

  • 接收数据解析函数 http_parse_request():
static err_t http_parse_request(struct pbuf **inp, struct http_state *hs, struct tcp_pcb *pcb)
{char *data;char *crlf;u16_t data_len;struct pbuf *p = *inp;char *sp1, *sp2;u16_t uri_len;char *uri;/* 排列字符串 */if (hs->req == NULL){hs->req = p;}else{/* 将多次的请求字符串进行连接排序 */pbuf_cat(hs->req, p);}/* 拷贝输入数据 */ if (hs->req->next != NULL){data_len = hs->req->tot_len;pbuf_copy_partial(hs->req, data, data_len, 0);}else{data = (char *)p->payload;data_len = p->len;}/* 提取接收到的浏览器字符串,浏览器请求示例:"GET / HTTP/1.1" */if (data_len > 7) {crlf = strstr(data, "\r\n");if (crlf != NULL) {/* 比较前4个字符是否为 "GET " */if (strncmp(data, "GET ", 4) == 0) {/* sp1指向字符串 "/ HTTP/1.1" */sp1 = (data + 4);}/* 在sp1字符串中寻找字符" ",sp2指向字符串 " HTTP/1.1" */sp2 = strstr(sp1, " ");/* uri_len获取sp1字符串首地址到sp2字符串首地址的长度 */uri_len = sp2 - (sp1);if ((sp2 != 0) && (sp2 >= (sp1))) {/* 将解析的字符串赋给uri,并在最后加上结束符\0,uri指向字符串 "/\0" */uri = sp1;*(sp1 - 1) = 0;uri[uri_len] = 0;/* 根据字符串寻找对应网页数据 */return http_find_file(hs, uri, 0); }}}return ERR_OK;
}

小结:这个函数是重要的请求数据解析函数,函数将接收到的字符串(例:“GET /STM32F4x7_files/ST.gif HTTP/1.1”)
分离出重要的判断字符串(例:“ /STM32F4x7_files/ST.gif”),然后根据这个字符串的内容来读取对应的网页数据;

  • 读取对应网页数据函数 http_find_file():
static err_t http_find_file(struct http_state *hs, const char *uri, int is_09)
{struct fs_file *file = NULL;/* 如果字符串为 "/\0",则打开index网页 */if((uri[0] == '/') && (uri[1] == 0)) {file = fs_open("/index.html");uri = "/index.html";} else {/* 如果为其他请求,则打开相应网页 */file = fs_open(uri);}/* 将网页文件数据赋值给http_state结构体,之后发送出去 */return http_init_file(hs, file, is_09, uri);
}

小结:此函数就是网页数据读取函数,里面最重要的函数就是 fs_open() 函数了,这个函数在官方建立web服务器工程里的 fs.c 文件里面,这个函数的解析放到后面;

ps:http_server.c 还有头文件的包含,函数的定义;另外再编写一个http_server.h文件,包含宏定义,结构体定义,函数定义;在下面贴出这两个文件的源码;

上面基本包括了几个重要的函数,当然还有其他的函数,包括发送函数等等,这些函数可以看源代码的注释来理解


文件源码##

  • http_server.c
#include "lwip/debug.h"
#include "lwip/stats.h"
#include "lwip/tcp.h"
#include "http_server.h"
#include "fs.h"#include <string.h>
#include <stdio.h>
#include <stdlib.h>/*
*********************************************************************************************************
*                                            LOCAL TABLES
*********************************************************************************************************
*/
static err_t http_server_accept(void *arg, struct tcp_pcb *pcb, err_t err);
static err_t http_server_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *tcp_recv_pbuf, err_t err);
static err_t http_server_poll(void *arg, struct tcp_pcb *pcb);
static err_t http_init_file(struct http_state *hs, struct fs_file *file, int is_09, const char *uri);
static err_t http_find_file(struct http_state *hs, const char *uri, int is_09);
static err_t http_parse_request(struct pbuf **inp, struct http_state *hs, struct tcp_pcb *pcb);
static u8_t http_send_data(struct tcp_pcb *pcb, struct http_state *hs);
static err_t http_sent(void *arg, struct tcp_pcb *pcb, u16_t len);
static void close_conn(struct tcp_pcb *pcb, struct http_state *hs);/*
*********************************************************************************************************
*                                      LOCAL FUNCTION PROTOTYPES
*********************************************************************************************************
*//**** 函数名称 : Http_Server_Init();** 函数描述 : web服务器初始化;** 传递值      : 无;** 返回值   : 无;***/
void Http_Server_Init(void)
{struct tcp_pcb *http_server_pcb;/* 为web服务器分配一个tcp_pcb结构体 */http_server_pcb = tcp_new();/* 绑定本地端号和IP地址 */tcp_bind(http_server_pcb, IP_ADDR_ANY, 80);/* 监听之前创建的结构体http_server_pcb */http_server_pcb = tcp_listen(http_server_pcb);/* 初始化结构体接收回调函数 */tcp_accept(http_server_pcb, http_server_accept);
}/**** 函数名称 : http_server_accept();** 函数描述 : lwip数据接收回调函数,包含对tcp连接的确认,接收回调函数的配置;** 传递值      : *arg, *pcb, err ;** 返回值   : ERR_OK 无错误;***/
static err_t http_server_accept(void *arg, struct tcp_pcb *pcb, err_t err)
{struct http_state *hs;/* 分配内存空间 */hs = (struct http_state *)mem_malloc(sizeof(struct http_state));if (hs != NULL){memset(hs, 0, sizeof(struct http_state));}/* 确认监听和连接 */tcp_arg(pcb, hs);/* 配置接收回调函数 */tcp_recv(pcb, http_server_recv);/* 配置轮询回调函数 */tcp_poll(pcb, http_server_poll, 4);/* 配置发送回调函数 */tcp_sent(pcb, http_sent);return ERR_OK;
}/**** 函数名称 : http_server_recv();** 函数描述 : 接受到数据后,根据接收到数据的内容,返回网页;** 传递值    : *arg, *pcb, *http_recv_pbuf, err;** 返回值   : ERR_OK无错误;***/
static err_t http_server_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *http_recv_pbuf, err_t err)
{err_t parsed = ERR_ABRT;struct http_state *hs = (struct http_state *)arg;/* 告诉tcp已经接收到数据 */tcp_recved(pcb, http_recv_pbuf->tot_len);if (hs->handle == NULL){/* 解析接收到的浏览器请求数据 */parsed = http_parse_request(&http_recv_pbuf, hs, pcb);}/* 清空请求字符串 */if (parsed != ERR_INPROGRESS) {     if (hs->req != NULL) {pbuf_free(hs->req);hs->req = NULL;}}if (parsed == ERR_OK){/* 发送网页数据 */http_send_data(pcb, hs);}else if (parsed == ERR_ARG){/* 关闭连接 */close_conn(pcb, hs);}return ERR_OK;
}/**** 函数名称 : http_server_poll();** 函数描述 : 轮询函数;** 传递值    : *arg, *pcb;** 返回值   : ERR_OK无错误;***/
static err_t http_server_poll(void *arg, struct tcp_pcb *pcb)
{struct http_state *hs = arg;if (hs == NULL){close_conn(pcb, hs);return ERR_OK;}else{hs->retries++;if (hs->retries == 4){close_conn(pcb, hs);return ERR_OK;}/* 如果连接存在打开的文件,则将会发送剩下的数据;* 如果一直没有收到GET请求,那么连接将会立刻关闭 */if (hs && (hs->handle)){if (http_send_data(pcb, hs)){tcp_output(pcb);}}}return ERR_OK;
}/**** 函数名称 : http_parse_request();** 函数描述 : 对接收到的数据进行解析,根据不同的浏览器请求,返回对应的网页数据;** 传递值    : **inp, *hs, *pcb;** 返回值   : ERR_OK无错误;***/
static err_t http_parse_request(struct pbuf **inp, struct http_state *hs, struct tcp_pcb *pcb)
{char *data;char *crlf;u16_t data_len;struct pbuf *p = *inp;char *sp1, *sp2;u16_t uri_len;char *uri;/* 排列字符串 */if (hs->req == NULL){hs->req = p;}else{/* 将多次的请求字符串进行连接排序 */pbuf_cat(hs->req, p);}/* 拷贝输入数据 */ if (hs->req->next != NULL){data_len = hs->req->tot_len;pbuf_copy_partial(hs->req, data, data_len, 0);}else{data = (char *)p->payload;data_len = p->len;}/* 提取接收到的浏览器字符串,浏览器请求示例:"GET / HTTP/1.1" */if (data_len > 7) {crlf = strstr(data, "\r\n");if (crlf != NULL) {/* 比较前4个字符是否为 "GET " */if (strncmp(data, "GET ", 4) == 0) {/* sp1指向字符串 "/ HTTP/1.1" */sp1 = (data + 4);}/* 在sp1字符串中寻找字符" ",sp2指向字符串 " HTTP/1.1" */sp2 = strstr(sp1, " ");/* uri_len获取sp1字符串首地址到sp2字符串首地址的长度 */uri_len = sp2 - (sp1);if ((sp2 != 0) && (sp2 >= (sp1))) {/* 将解析的字符串赋给uri,并在最后加上结束符\0,uri指向字符串 "/\0" */uri = sp1;*(sp1 - 1) = 0;uri[uri_len] = 0;/* 根据字符串寻找对应网页数据 */return http_find_file(hs, uri, 0); }}}return ERR_OK;
}/**** 函数名称 : http_find_file();** 函数描述 : 对提取的数据进行判断,读取对应的网页数据;** 传递值   : *hs, *uri, is_09;** 返回值   : ERR_OK无错误;***/
static err_t http_find_file(struct http_state *hs, const char *uri, int is_09)
{struct fs_file *file = NULL;/* 如果字符串为 "/\0",则打开index网页 */if((uri[0] == '/') && (uri[1] == 0)) {file = fs_open("/index.html");uri = "/index.html";} else {/* 如果为其他请求,则打开相应网页 */file = fs_open(uri);}/* 将网页文件数据赋值给http_state结构体,之后发送出去 */return http_init_file(hs, file, is_09, uri);
}/**** 函数名称 : http_init_file();** 函数描述 : 将要发送的数据保存到http_state结构体当中;** 传递值     : *hs, *file, is_09, *uri;** 返回值   : ERR_OK无错误;***/
static err_t http_init_file(struct http_state *hs, struct fs_file *file, int is_09, const char *uri)
{if (file != NULL) {hs->handle = file;/* 将网页数据赋值给http_state */hs->file = (char*)file->data;/* 将网页长度赋值给http_state */hs->left = file->len;hs->retries = 0;} else {hs->handle = NULL;hs->file = NULL;hs->left = 0;hs->retries = 0;}return ERR_OK;
}/**** 函数名称 : http_send_data();** 函数描述 : 数据发送函数;** 传递值    : *pcb, *hs;** 返回值   : ERR_OK无错误;***/
static u8_t http_send_data(struct tcp_pcb *pcb, struct http_state *hs)
{err_t err = ERR_OK;u16_t len;u8_t data_to_send = 0;/* 配置发送数据长度,如果发送数据过长则分批发送 */if (tcp_sndbuf(pcb) < hs->left){len = tcp_sndbuf(pcb);}else{len = (u16_t)hs->left;}     /* 发送网页数据 */err = tcp_write(pcb, hs->file, len, 1);if (err == ERR_OK){data_to_send = 1;hs->file += len;hs->left -= len;}if ((hs->left == 0) && (fs_bytes_left(hs->handle) <= 0)){/* 关闭连接 */close_conn(pcb, hs);return 0;}return data_to_send;
}/**** 函数名称 : http_sent();** 函数描述 : 数据已经被发送,并且被远程主机确定;** 传递值   : *arg, *pcb, len;** 返回值   : ERR_OK无错误;***/
static err_t http_sent(void *arg, struct tcp_pcb *pcb, u16_t len)
{struct http_state *hs = (struct http_state *)arg;if (hs == NULL){return ERR_OK;}hs->retries = 0;http_send_data(pcb, hs);return ERR_OK;
}/**** 函数名称 : close_conn();*  * 函数描述 : 关闭tcp连接;*  * 传递值   : *pcb, *hs;*  * 返回值   : 无;*  **/
static void close_conn(struct tcp_pcb *pcb, struct http_state *hs)
{tcp_arg(pcb, NULL);tcp_recv(pcb, NULL);tcp_err(pcb, NULL);tcp_poll(pcb, NULL, 0);tcp_sent(pcb, NULL);if (hs != NULL) {if(hs->handle) {fs_close(hs->handle);hs->handle = NULL;}mem_free(hs);}tcp_close(pcb);
}
  • http_server.h
#ifndef HTTP_SERVER_H
#define HTTP_SERVER_H/*
*********************************************************************************************************
*                                              INCLUDE FILES
*********************************************************************************************************
*//*
*********************************************************************************************************
*                                               CONSTANTS
*********************************************************************************************************
*//*
*********************************************************************************************************
*                                             PERIPH DEFINES
*********************************************************************************************************
*//*
*********************************************************************************************************
*                                               DATA TYPES
*********************************************************************************************************
*//*
*********************************************************************************************************
*                                            GLOBAL VARIABLES
*********************************************************************************************************
*/struct http_state {struct fs_file *handle;char *file;       /* Pointer to first unsent byte in buf. */#if 1struct pbuf *req;
#endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */#if 1char *buf;        /* File read buffer. */int buf_len;      /* Size of file read buffer, buf. */
#endif /* LWIP_HTTPD_SSI || LWIP_HTTPD_DYNAMIC_HEADERS */u32_t left;       /* Number of unsent bytes in buf. */u8_t retries;
#if 0const char *parsed;     /* Pointer to the first unparsed byte in buf. */
#if 1const char *tag_started;/* Poitner to the first opening '<' of the tag. */
#endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG */const char *tag_end;    /* Pointer to char after the closing '>' of the tag. */u32_t parse_left; /* Number of unparsed bytes in buf. */u16_t tag_index;   /* Counter used by tag parsing state machine */u16_t tag_insert_len; /* Length of insert in string tag_insert */
#if 0u16_t tag_part; /* Counter passed to and changed by tag insertion function to insert multiple times */
#endif /* LWIP_HTTPD_SSI_MULTIPART */u8_t tag_check;   /* true if we are processing a .shtml file else false */u8_t tag_name_len; /* Length of the tag name in string tag_name */char tag_name[LWIP_HTTPD_MAX_TAG_NAME_LEN + 1]; /* Last tag name extracted */char tag_insert[LWIP_HTTPD_MAX_TAG_INSERT_LEN + 1]; /* Insert string for tag_name */enum tag_check_state tag_state; /* State of the tag processor */
#endif /* LWIP_HTTPD_SSI */
#if 0char *params[LWIP_HTTPD_MAX_CGI_PARAMETERS]; /* Params extracted from the request URI */char *param_vals[LWIP_HTTPD_MAX_CGI_PARAMETERS]; /* Values for each extracted param */
#endif /* LWIP_HTTPD_CGI */
#if 0const char *hdrs[NUM_FILE_HDR_STRINGS]; /* HTTP headers to be sent. */u16_t hdr_pos;     /* The position of the first unsent header byte in thecurrent string */u16_t hdr_index;   /* The index of the hdr string currently being sent. */
#endif /* LWIP_HTTPD_DYNAMIC_HEADERS */
#if 0u32_t time_started;
#endif /* LWIP_HTTPD_TIMING */
#if 0u32_t post_content_len_left;
#if 0u32_t unrecved_bytes;struct tcp_pcb *pcb;u8_t no_auto_wnd;
#endif /* LWIP_HTTPD_POST_MANUAL_WND */
#endif /* LWIP_HTTPD_SUPPORT_POST*/
};/*
*********************************************************************************************************
*                                                 MACRO'S
*********************************************************************************************************
*//*
*********************************************************************************************************
*                                           FUNCTION PROTOTYPES
*********************************************************************************************************
*/void Http_Server_Init(void);/*
********************************************************************************************************
*                                             MODULE END
*********************************************************************************************************
*/#endif /* HTTP_SERVER_H */

官方部分函数解析

读取网页数据文件 fs.c (路径:Project->Standalone->web_server->http):

struct fs_file *fs_open(const char *name)
{struct fs_file *file;const struct fsdata_file *f;/* 分配空间 */file = fs_malloc();if(file == NULL) {return NULL;}for(f = FS_ROOT; f != NULL; f = f->next) {/* 循环比较,如果输入的请求与网页的头数据一致,则返回该网页数据 */if (!strcmp(name, (char *)f->name)) {file->data = (const char *)f->data;file->len = f->len;file->index = f->len;file->pextension = NULL;file->http_header_included = f->http_header_included;return file;}}fs_free(file);return NULL;
}

这里关注 f 变量的结构体 fsdata_file,定义在 fsdata.h:

struct fsdata_file
{const struct fsdata_file *next;const unsigned char *name;const unsigned char *data;int len;u8_t http_header_included;
};

**结构体中有三个重要的变量*next、name、data
而在文件fsdata.c中,拉到最后,发现有几个 fsdata_file 的结构体变量,取其中一个来解析一下:

const struct fsdata_file file__index_html[] =
{ {/* 变量*next,指向下一个要循环比较的数据 */file__404_html,/* 变量*name,指向数据数组 data__index_html[] */data__index_html,/* 变量*data,指向数据数组 data__index_html[]12个之后的数据 */data__index_html + 12,/* 网页数据长度 */sizeof(data__index_html) - 12,1,}
};
  • 变量*name指向的数组前12个数据是字符串 “/index.html” 的ascii码,用于与输入的浏览器请求 “GET /index.html HTTP/1.1” 进行对比;
  • 而*data指向数组的12个后的数据,便是网页源代码的16进制数据,这些数据将会由发送函数发送给浏览器,使浏览器显示网页;

web服务器测试

将工程编译后,烧进stm32,将网线与pc机连接:

  • 打开浏览器(谷歌浏览器测试)
  • 输入服务器ip(这里搭建的服务器ip:192.168.0.10),Enter;
  • 浏览器会显示网页,点击网页上的按钮即可以切换不同的网页

如图:


总结:从上面的一系列过程可以get到搭建web服务器的核心思想,然而,现在并没有加入ssi和cgi,所以还无法用网页控制stm32,后面会加上ssi、cgi、post与get请求来完善整个web服务器;

ps:有部分细节的地方解析的不是很清楚,而且自己也没有想明白,需要再加把劲看一些其他的资料来填补空白,共勉~

STM32移植lwip之建立web服务器相关推荐

  1. STM32+ENC28J60+UIP协议栈实现WEB服务器示例

    一.环境介绍 MCU:  STM32F103ZET6 网卡: ENC28J60 协议栈: UIP 开发软件: Keil5 二.功能介绍 完整项目源码下载链接:https://download.csdn ...

  2. goaheadlinux移植_goahead(嵌入式Web服务器)之交叉编译、移植篇

    GoAhead简介: GoAhead是一个开源(商业许可).简单.轻巧.功能强大.可以在多个平台运行的嵌入式Web Server. GoAhead主要特性: 1 很小的内存消耗 2 支持认证功能Dig ...

  3. 一文搞定stm32移植LWIP及代码逻辑

    文章目录 一,使用以太网的库 二,ST以太网驱动库的移植 1,stm32f4x7_eth.c 2,lan8720.c 三,移植LWIP协议栈 1,lwip_comm.c 2,ethernetif.c ...

  4. goaheadlinux移植_goAhead2.5嵌入式web服务器移植

    1. GoAhead Web服务器介绍 goAhead Web服务器,小巧.精致,提供了值得称道的性能,特别适合于嵌入式系统,因此,在很多嵌入式产品如路由器中都用到了goAhead作为嵌入式web服务 ...

  5. 嵌入式如何移植php,关于嵌入式web服务器的移植

    目标:静态编译 版本:apache-1.3.39 + php-5.5.5 PC环境:ubuntu16 交叉编译工具链:arm-linux-gcc 首先可以参考:https://www.cnblogs. ...

  6. STM32移植LWIP

    目录 01.IAR工程移植 02.修改Keil工程 在上篇文章<LWIP初体验-修改ST官方demo>中我们已经在自己的开发板上实现了简单的TCPsever和TCPclient功能.验证完 ...

  7. STM32移植LWIP网线热插入网络不通的解决办法

    开发背景: 1.主芯片-STM32F207VCT6: 2.TCP/IP协议栈-LWIP,依托ST例程移植: 3.操作系统-无(裸机): 异常现象: 1.网线不插入的情况下先给设备上电,之后再插入网线无 ...

  8. 利用python自带的包可以建立简单的web服务器

    2019独角兽企业重金招聘Python工程师标准>>> ##一个命令建立一个简单web服务器 python -m SimpleHTTPServer port 例如:python -m ...

  9. ipad php mysql_如何用PHP/MySQL为 iOS App 写一个简单的web服务器(译) PART1

    原文:http://www.raywenderlich.com/2941/how-to-write-a-simple-phpmysql-web-service-for-an-ios-app 作为一个i ...

最新文章

  1. C语言文件操作解析(二)【转载】
  2. mysql主节点数据恢复_Mysql 主从复制+数据恢复
  3. C:#define用法
  4. Struts2和Spring和Hibernate应用实例
  5. 使用border制作的css三角形
  6. 换一种姿势:利用 PdaNet+ 实现电脑共享手机的流量
  7. 【安装版】mysql数据库安装指南(超级详细)
  8. 树的计数 Prufer序列+Cayley公式
  9. bzoj5064 B-number 数位dp
  10. win10网络适配器不见了_win10没有网络适配器怎么办
  11. 信息系统项目管理9大知识领域及其概要说明
  12. 如何在浏览器中打开jupyter notebook
  13. 2019牛客暑期多校训练营(第九场)A——The power of Fibonacci(循环节+中国剩余定理(互质)||广义BM)
  14. 2021-12-17
  15. python 自动上色_Github | 线稿自动上色
  16. 西门子PPI协议的工控通信控件
  17. 如何灵活使用ASCII编码
  18. java之CSV大批量数据入库
  19. 网狐棋牌QueueService
  20. Arduino读取HC-SR04超声波测距传感器数据附带滤波

热门文章

  1. 蜂鸟E203 SOC开源资料汇总 及 RISC-V基础
  2. 算法刷题打卡第76天:判断矩阵是否是一个 X 矩阵
  3. weui 加载提示_WEUI滚动加载
  4. 设置电脑网络唤醒-华硕主板+向日葵
  5. 2023版毛概+习概(习思想)课后题及答案整理
  6. 被忽略的错误——这个我一直都是这么写的啊!
  7. git prune 分支清除
  8. 【LaTeX】如何愉快地肝report —— VS Code × LaTeX
  9. Pytorch 中的 non_blocking
  10. 澳大利亚降雨预测(基于四种机器学习算法)