C语言编写web server

大部分的web server都是用JAVA、JS做的,查找了许多资料github上也只有寥寥数篇的几篇帖子,能用的真不多。后来经同事帮助在《嵌入式网络那些事STM32物联实战》这本书上找到了基于协议栈LWIP的web  server,建立服务器需要对HTTP协议、html网页有所了解,这样更利于设计代码完善功能(公司要求功能简单点灯、OTA升级、PWM波形输出、mesh网络配置)。 

github示例:https://github.com/volkanunal/LwipFreertosWebServer 

废话不多说直接上代码

一、tcp接口实现


#define HTTP_PORT 80
const unsigned char htmldata[] = "	\
        	\
         A LwIP WebServer !! \
	    

A WebServer Based on LwIP v1.4.1!

\ "; static err_t http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) { char *data = NULL; /* We perform here any necessary processing on the pbuf */ if (p != NULL) { /* We call this function to tell the LwIp that we have processed the data */ /* This lets the stack advertise a larger window, so more data can be received*/ tcp_recved(pcb, p->tot_len); data = p->payload; if(p->len >=3 && (strncmp(data, "GET /", 5) == 0) { tcp_write(pcb, htmldata, sizeof(htmldata), 1); } else { printf("Request error\n"); } pbuf_free(p); tcp_close(pcb); //断开连接,有可能导致打开不了网页 } else if (err == ERR_OK) { /* When the pbuf is NULL and the err is ERR_OK, the remote end is closing the connection. */ /* We free the allocated memory and we close the connection */ return tcp_close(pcb); } return ERR_OK; } /** * @brief This function when the Telnet connection is established * @param arg user supplied argument * @param pcb the tcp_pcb which accepted the connection * @param err error value * @retval ERR_OK */ static err_t http_accept(void *arg, struct tcp_pcb *pcb, err_t err) { tcp_recv(pcb, http_recv); return ERR_OK; } /** * @brief Initialize the http application * @param None * @retval None */ static void http_server_init(void) { struct tcp_pcb *pcb = NULL; /* Create a new TCP control block */ pcb = tcp_new(); /* Assign to the new pcb a local IP address and a port number */ /* Using IP_ADDR_ANY allow the pcb to be used by any local interface */ tcp_bind(pcb, IP_ADDR_ANY, HTTP_PORT); /* Set the connection to the LISTEN state */ pcb = tcp_listen(pcb); /* Specify the function to be called when a connection is established */ tcp_accept(pcb, http_accept); }

注意:1.一般会先发送消息报头head

例如:const static char http_html_hdr[] = "HTTP/1.1 200 OK\r\nContent-type:text/html\r\n\r\n";

但是现在直接发送网页实体也能正常显示网页,不同浏览器兼容性问题也会有影响

二、lwip的API接口实现网页控灯

const static char http_html_hdr[] = "HTTP/1.1 200 OK\r\nContent-type:text/html\r\n\r\n";

const unsigned char LedOn_Data[] = "\
    \
    \
    \
    \
    LED Monitor\
    \
	
\

\

LED 已打开!
\
\ 改变LED状态: \ \
\

\
\ \ "; const unsigned char LedOff_Data[] = "\ \ \ \ \ LED Monitor\ \
\

\

LED 已关闭!
\
\ 改变LED状态: \ \
\

\
\ \ "; const unsigned char testData[] = "\ 1"; static bool led_on = FALSE; void httpserver_send_html(struct netconn *conn, bool led_status) { err_t err; //err = netconn_write(conn, http_html_hdr, sizeof(http_html_hdr)-1, NETCONN_NOCOPY); //不发送head的原因是发送了头,网页显示不了,空白,但可以和实体的数组合并一起发送,这样会更稳定 printf("err = %d\n", err); if(led_status == TRUE) { netconn_write(conn, LedOn_Data, sizeof(LedOn_Data)-1, NETCONN_NOCOPY); } else { err = netconn_write(conn, LedOff_Data, sizeof(LedOff_Data)-1, NETCONN_NOCOPY); printf("err = %d\n", err); printf("%s,%d\n",__func__,__LINE__); } printf("%s,%d\n",__func__,__LINE__); } void httpserver_serve(struct netconn *conn) { struct netbuf *inbuf; err_t recv_err; char *buf; u16_t buflen; recv_err = netconn_recv(conn, &inbuf); printf("%s,%d\n",__func__,__LINE__); if(recv_err == ERR_OK) { if(netconn_err(conn) == ERR_OK) { netbuf_data(inbuf, (void**)&buf, &buflen); printf("%s,%d\n",__func__,__LINE__); if((buflen >= 5) && (strncmp(buf, "GET /", 5) == 0)) { httpserver_send_html(conn, led_on); printf("%s,%d\n",__func__,__LINE__); } else if((buflen >= 8) && (strncmp(buf, "POST", 4) == 0)) { printf("%s,%d\n",__func__,__LINE__); if(buf[6] == '0' && buf[7] == 'n') { led_on = TRUE; LED_ON(); //自己根据情况在这设置 } else if(buf[6] == '0' && buf[7] == 'f' && buf[8] == 'f') { led_on = FALSE; LED_OFF(); } httpserver_send_html(conn, led_on); } } netbuf_delete(inbuf); } netconn_close(conn); } static void httpserver_thread(void *arg) { struct netconn *conn, *newconn; err_t err; LWIP_UNUSED_ARG(arg); /* Create a new TCP connection handle */ conn = netconn_new(NETCONN_TCP); LWIP_ERROR("http_server: invalid conn", (conn != NULL), return;); led_on = TRUE; LED_ON(); //根据实际情况编写函数 /* Bind to port 80 (HTTP) with default IP address */ netconn_bind(conn, NULL, 80); /* Put the connection into LISTEN state */ netconn_listen(conn); do { err = netconn_accept(conn, &newconn); if (err == ERR_OK) { httpserver_serve(newconn); netconn_delete(newconn); } } while(err == ERR_OK); LWIP_DEBUGF(HTTPD_DEBUG, ("http_server_netconn_thread: netconn_accept received error %d, shutting down", err)); netconn_close(conn); netconn_delete(conn); } /** Initialize the HTTP server (start its thread) */ //根据自身情况启用线程 void httpserver_init() { sys_thread_new("http_server_netconn", httpserver_thread, NULL, DEFAULT_THREAD_STACKSIZE, TCPIP_THREAD_PRIO + 1); }

 开启web server之前需要先保持开发板与服务器端处于同一网段,并能ping通,推荐使用google浏览器进行调试

在公司进行开发时还是要多进行debug和实验调试,祝大家早日完成任务

 

你可能感兴趣的:(工作)