In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-25 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/01 Report--
This article will explain in detail how to build http server in LwIP raw api. The content of the article is of high quality, so the editor shares it for you as a reference. I hope you will have some understanding of the relevant knowledge after reading this article.
The following is to build the learning record of HTTP SERVER DEMO under LwIP RAW API, the content is only for personal design and understanding, the code posted is a simplified version, does not guarantee applicability and accuracy.
The LwIP version I use is 2.1.2. The direct interface of the LwIP application layer is ALTCP, and there is an abstraction layer on top of the TCP. You can also use the macro switch LWIP_ALTCP to make the interface directly correspond to the TCP function.
I. Service initialization
Void http_init (void) {struct altcp_pcb * pcb; / / allocation protocol control block pcb = altcp_tcp_new_ip_type (IPADDR_TYPE_ANY); / / mount interface altcp_bind (pcb, IP_ANY_TYPE, 80); / / enable listening pcb = altcp_listen (pcb); / / register receive callback altcp_accept (pcb, http_accept);}
The initialization is to allocate the protocol control block, bind it to the http port number 80, and then wait for the client to connect.
The control block pcb is created by calling the TCP API tcp_new_ip_type in the altcp_tcp_new_ip_type function, and then the altcp_pcb control block ret is defined. After clipping the pcb, several parts of the LwIP concern are connected to the ret. The upper application only needs to care about the castrated ret without looking at the complete TCP control block structure, and the callback of the application layer only needs to be docked with the altcp_pcb. If there is insufficient space, TCP will release some inactive control blocks, and altcp will only reply failure due to insufficient space left in MEMP.
Pcb- > callback_arg = altcp_pcb
Pcb- > recv = altcp_tcp_recv
Pcb- > sent = altcp_tcp_sent
Pcb- > errf = altcp_tcp_err
Struct altcp_pcb * altcp_tcp_new_ip_type (u8pragt ip_type) {/ * Allocate the tcp pcb first to invoke the priority handling code if we're out of pcbs * / struct tcp_pcb * tpcb = tcp_new_ip_type (ip_type); if (tpcb! = NULL) {struct altcp_pcb * ret = altcp_alloc (); if (ret! = NULL) {altcp_tcp_setup (ret, tpcb); return ret } else {/ * altcp_pcb allocation failed-> free the tcp_pcb too * / tcp_close (tpcb);}} return NULL;}
There is also an altcp_new_ip_type allocation method on which user-defined alloc functions and parameters can be saved in the altcp_allocator_t structure variables they call.
Altcp_bind directly manipulates altcp_tcp_bind and actually uses tcp_bind to bind pcb corresponding to altcp_pcb and http port number 80. TCP traverses the existing control block linked list and inserts the linked list if it does not have the same IP and port number.
Altcp_listen (conn) starts the server listening state, and its actual function altcp_tcp_listen also calls tcp_listen_with_backlog_and_err. Because TCP snooping replaces tcp_pcb with resource-saving tcp_pcb_listen structure variables, the state element needs to be updated. Then connect altcp_tcp_accept with tcp_accept as the callback of client connection. When TCP_EVENT_ACCEPT occurs, it opens up a new altcp_pcb to dock the new_tpcb of client connection, and executes the preset accept function in arg (pcb- > callback_arg- > accept, that is, altcp_pcb- > accept).
Static struct altcp_pcb * altcp_tcp_listen (struct altcp_pcb * conn, u8roomt backlog, err_t * err) {struct tcp_pcb * pcb; struct tcp_pcb * lpcb; if (conn = = NULL) {return NULL;} ALTCP_TCP_ASSERT_CONN (conn); pcb = (struct tcp_pcb *) conn- > state; lpcb = tcp_listen_with_backlog_and_err (pcb, backlog, err); if (lpcb! = NULL) {conn- > state = lpcb Tcp_accept (lpcb, altcp_tcp_accept); return conn;} return NULL;}
Altcp_accept is a http_accept that registers the callback passed to LwIP in the accept phase in the previous step to the application layer. In this function, the client connection request is processed and the complete connection operation is completed. Open a variable in the http_accept of the user layer to place the status of the application and the parameters of the callback in the lower layer, and associate it with the corresponding pcb, and then correspond each altcp callback of the LwIP that has been connected to the TCP to the specific processing function of the application layer.
# define HTTP_PRIO TCP_PRIO_MINstatic err_t http_accept (void * arg, struct altcp_pcb * pcb, err_t err) {struct http_st * st = http_state_alloc (); st- > pcb = pcb; altcp_arg (pcb, hs); altcp_setprio (pcb, HTTP_PRIO); altcp_recv (pcb, http_recv); altcp_poll (pcb, http_poll, HTTP_POLL_INT); altcp_sent (pcb, http_sent) Altcp_err (pcb, http_err); return ERR_OK;}
At this point, the initialization process of a service is basically completed, and then the function of the application layer is written.
Second, the function of application layer
The application layer processes the callback of the received data in the http_recv, where the structure pbuf is the packet decomposed by the protocol stack. In the data processing of raw api, the user is required to manually execute altcp_recved notification protocol stack data to receive correctly, and pbuf_free releases the packet cache.
Static err_t http_recv (void * arg, struct altcp_pcb * pcb, struct pbuf * p, err_t err) {struct http_st * st = (struct http_st *) arg; if ((p = = NULL) | | (err! = ERR_OK) | | (st = = NULL) {if (p! = NULL) {altcp_recved (pcb, p-> tot_len); pbuf_free (p);} http_close_conn (pcb, st) Return ERR_OK;} altcp_recved (pcb, p-> tot_len); if (st- > handle = = NULL) {err_t parsed = http_parse_request (p, st, pcb); pbuf_free (p); if (parsed = = ERR_OK) {http_send (pcb, st);} else if (parsed = = ERR_ARG) {http_close_conn (pcb, hs) }} else {pbuf_free (p);} return ERR_OK;}
The main function of the http_parse_request function is to parse the received HTTP protocol instructions and respond to the correct "GET". Http server stores the file_handle list in advance, and transfers the corresponding files when client sends the corresponding uri.
# define CRLF "\ r\ n" static err_t http_parse_request (struct pbuf * p, struct http_st * st, struct altcp_pcb * pcb) {char * data; u16dett data_len; if ((st- > handle! = NULL) | | (st- > file! = NULL) {/ / already started sending return ERR_USE;} / / actual data in pbuf data = (char *) p-> payload; / / length of current buffer data_len = p-> len / * find first\ r\ n * / if (lwip_strnstr (data, CRLF, data_len)! = NULL) {char * sp1, * sp2; int is_09 = 0; u16% left_len, uri_len; if (strncmp (data, "GET", 4)) {/ / unsupported http_find_error_file (st, 501);} sp1 = data + 3 / / check URI left_len = (u16Secrett) (data_len-((sp1 + 1)-data)); sp2 = lwip_strnstr (sp1 + 1, ", left_len); if (sp2 = = NULL) {sp2 = lwip_strnstr (sp1 + 1, CRLF, left_len); is_09 = 1;} uri_len = (u16Secrett) (sp2-(sp1 + 1)) If ((sp2! = 0) & & (sp2 > sp1)) {/ / find the end of HTTP headers if (lwip_strnstr (data, CRLF CRLF, data_len)! = NULL) {char * uri = sp1 + 1; * sp1 = 0; Uri [Uri _ len] = 0; return http_find_file (st, uri, is_09) } return http_find_error_file (st, 400);} static err_t http_find_error_file (struct http_st * st, u16Secrett error_nr) {const char * uri, * uri1, * uri2, * uri3; if (error_nr = 501) {uri1 = "/ 501.html"; uri2 = "/ 501.htm"; uri3 = "/ 501.shtml" } else {/ * 400 (bad request is the default) * / uri1 = "/ 400.html"; uri2 = "/ 400.htm"; uri3 = "/ 400.shtml";} if (fs_open (& st- > file_handle, uri1) = = ERR_OK) {uri = uri1;} else if (fs_open (& st- > file_handle, uri2) = ERR_OK) {uri = uri2 } else if (fs_open (& st- > file_handle, uri3) = ERR_OK) {uri = uri3;} else {return ERR_ARG;} return http_init_file (st, & st- > file_handle, 0, uri, 0, NULL);}
According to the parsed uri, look for the corresponding name file in the local file
# define LWIP_HTTP_MAX_REQUEST_URI_LEN 63static char http_uri_ buf [LWIP _ HTTP_MAX_REQUEST_URI_LEN + 1]; static err_t http_find_file (struct http_st * st, const char * uri, int is_09) {size_t loop; struct fs_file * file = NULL; char * params = NULL; err_t err; int i; u8 tag_check = 0; / check uri size_t uri_len = strlen (uri) If ((uri_len > 0) & & (uri [uri _ len-1] = ='/') & & ((uri! = http_uri_buf) | | (uri_len = = 1)) {size_t copy_len = LWIP_MIN (sizeof (http_uri_buf)-1, uri_len-1); if (copy_len > 0) {MEMCPY (http_uri_buf, uri, copy_len) Http_uri_ buf [copy _ len] = 0;} for (loop = 0; loop)
< NUM_DEFAULT_FILENAMES; loop++) { const char *file_name; if(copy_len >0) {size_t len_left = sizeof (http_uri_buf)-copy_len-1; if (len_left > 0) {size_t name_len = strlen (httpd_default_ filenames [loop] .name); size_t name_copy_len = LWIP_MIN (len_left, name_len) MEMCPY (& http_uri_ buf [copy _ len], httpd_default_ filenames [loop] .name, name_copy_len); http_uri_ buf [copy _ len + name_copy_len] = 0;} file_name = http_uri_buf;} else {file_name = httpd_default_ filenames [loop] .name } err = fs_open (& st- > file_handle, file_name); if (err = = ERR_OK) {uri = file_name; file = & st- > file_handle; tag_check = httpd_default_ filenamesloop] .shtml;}} if (file = = NULL) {params = (char *) strchr (uri,'?') If (params! = NULL) {* params ='\ 0mm; params++;} http_cgi_paramcount =-1; if (httpd_num_cgis & & httpd_cgis) {for (I = 0; I)
< httpd_num_cgis; i++) { if(strcmp(uri, httpd_cgis[i].pcCGIName) == 0) { http_cgi_paramcount = extract_uri_parameters(hs, params); uri = httpd_cgis[i].pfnCGIHandler(i, http_cgi_paramcount, st->Params, st- > param_vals); break;}} err = fs_open (& st- > file_handle, uri); if (err = = ERR_OK) {file = & st- > file_handle;} else {file = http_get_404_file (st, & uri) } if (file! = NULL) {if (file- > flags & FS_FILE_FLAGS_SSI) {tag_check = 1;} else {tag_check = http_uri_is_ssi (file, uri) }} if (file = = NULL) {/ * None of the default filenames exist so send back a 404 page * / file = http_get_404_file (st, & uri);} return http_init_file (st, file, is_09, uri, tag_check, params);}
Mount the found files to the state quantity st
Static err_t http_init_file (struct http_st * st, struct fs_file * file, int is_09, const char * uri, u8roomt tag_check, char * params) {if (file! = NULL) {if (tag_check) {struct http_ssi_state * ssi = http_ssi_state_alloc (); if (ssi! = NULL) {ssi- > tag_index = 0 Ssi- > tag_state = TAG_NONE; ssi- > parsed = file- > data; ssi- > parse_left = file- > len; ssi- > tag_end = file- > data; st- > ssi = ssi;}} st- > handle = file; st- > file = file- > data; st- > left = (u32ftt) file- > len; st- > retries = 0 If (is_09 & & ((st- > handle- > flags & FS_FILE_FLAGS_HEADER_INCLUDED)! = 0) {/ * HTTP/0.9 responses are sent without HTTP header, search for the end of the header. * / char * file_start = lwip_strnstr (st- > file, CRLF CRLF, st- > left); if (file_start! = NULL) {int diff = file_start + 4-st- > file; st- > file + = diff; st- > left-= (u32Secrett) diff;}} else {st- > handle = NULL; st- > file = NULL; st- > left = 0; st- > retries = 0 } if ((st- > handle = = NULL) | ((st- > handle- > flags & FS_FILE_FLAGS_HEADER_INCLUDED) = = 0) {get_http_headers (st, uri);} return ERR_OK;} so much about how to build http server in LwIP raw api. I hope the above can be helpful and learn more. If you think the article is good, you can share it for more people to see.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.