Arduino+w5100使用String类 解析GET请求-Arduino中文社区 - Powered by Discuz! Archiver

某1o 发表于 2015-11-7 21:44

Arduino+w5100使用String类 解析GET请求

本帖最后由 某1o 于 2015-11-7 22:35 编辑

大家肯定用过arduino内置的webserver例程,不过客户端请求是一个字符一个字符输出的,
没办法直接接收和处理信息,需要把这些字符连接起来再进行解析,在这里我使用了String这个类,
来方便的完成我们需要的功能。

首先来定义一个字符串型的变量res和一个整形变量resend
res用来存储请求信息 resend 用来控制结束接收
String res="" ;
int resend = 1;

设置resend初值为1
设置res初值为"",也就是没有东西,
不赋初值的话可能会发生一些不可预料的事情,因为编译器不会帮你把变量的初始值设置为空。

在接收请求之前 我们需要了解一下HTTP请求的格式:
GET /path/file?name=value HTTP/1.0换行符
HOST:myarduino.ip换行符

在这里 我们只需要接收一行请求,我们最终的目的是要获取GET 和HTTP中间的请求路径和表单信息

res接收客户端的请求

//前面省略一些代码 这些代码可以在arduinoIDE例程Webserver中找到
char c = client.read();//从客户端读取一个字符
//如果c接收到换行符res就停止接收,为了只读取一行请求
    if (c != '\n' && resend) {
          res += c;
      } else {
          resend = 0;
      }


经过多次循环res接收了一行请求,会停止再接收信息,以免干扰我们进行字符串拆分
如果要接收完整的请求 可以直接使用res += c; 去掉if语句使用。

接下来进行字符串的切割(Arduino官网的Wiki讲的很详细 https://www.arduino.cc/en/Reference/StringObject 大家可以详细阅读一下)
//判断字符串"GET “和" HTTP“在res中的位置,如不存在则值是-1   !=的意思是“不等于”
if ((res.indexOf("GET ") != -1) && (res.indexOf(" HTTP") != -1)) {
            //判断是否存在字符?
            if (res.indexOf('?') != -1) {
//从res中截取出GET表单数据 。res.substring(起始位置,结束位置)
            query = res.substring(res.indexOf('?') + 1, res.indexOf(" HTTP"));
//从res中截取出请求路径
            path = res.substring(res.indexOf("GET ") + 4, res.indexOf('?'));
            } else {
            path = res.substring(res.indexOf("GET ") + 4, res.indexOf(" HTTP"));
            }

res.substring(res.indexOf('?') + 1, res.indexOf(" HTTP"));
这行代码我来解释一下 res.substring(起始位置,结束位置)就是截取一个字符串的一部分字符,从”起始位置“一直截到”结束位置“
而括号里面的res.indexOf('?') 则是获取?这个字符在res这个字符串中最先出现的位置 +1就是?的下一个字符位置


PS:单个字符要用''单引号括起来 多个字符则需要用""双引号括起来!


现在GET请求就已经解析完了,path就是请求路径,query就是表单信息,
当然,也可以进一步处理,这里不再演示。


完整代码参考:
#include <SPI.h>
#include <Ethernet.h>

byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};//mac地址
IPAddress ip(192, 168, 31, 177);//ip地址
EthernetServer server(80);//访问端口
String fakename="Nginx/1.8.0 (Ubuntu 12.04 LTS)";//装逼参数(伪装服务器)

void setup() {
Serial.begin(9600);
while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
}
Ethernet.begin(mac, ip);
server.begin();
Serial.print("ip:");
Serial.println(Ethernet.localIP());
}


void loop() {
EthernetClient client = server.available();
if (client) {
    Serial.println("new client");
    String res="" ,query="",path="";
    int resend = 1;
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
      char c = client.read();
      //Serial.write(c);
      //只读取一行
      if (c != '\n' && resend) {
          res += c;
      } else {
          resend = 0;
      }

      if (c == '\n' && currentLineIsBlank) {
          //判断GET头完整性
          if ((res.indexOf("GET ") != -1) && (res.indexOf(" HTTP") != -1)) {
            //判断是否存在get参数
            if (res.indexOf('?') != -1) {
            query = res.substring(res.indexOf('?') + 1, res.indexOf(" HTTP"));
            path = res.substring(res.indexOf("GET ") + 4, res.indexOf('?'));
            } else {
            path = res.substring(res.indexOf("GET ") + 4, res.indexOf(" HTTP"));
            }
            
            Serial.println(res);
            Serial.println("GET:"+query);
            Serial.println("path:"+path);
            client.println("HTTP/1.1 200 OK");
            client.println("Server: "+fakename);//装逼参数
            client.println("Content-Type: text/html");
            client.println("Connection: close");
            client.println();
            client.println("<!DOCTYPE HTML><html><head></head><body><h1>200 Success</h1>GET:"+query+"<br />PATH:"+path+"<hr /><p>"+fakename+"</p></body></html>");
            break;
          } else {
            //GET头不完整 返回错误信息
            client.println("HTTP/1.1 403 Forbidden");
            client.println("Server: "+fakename);//装逼参数(伪装服务器)
            client.println("Content-Type: text/html");
            client.println("Connection: close");
            client.println();
            client.println("<!DOCTYPE HTML><html><head></head><body><h1>403 Forbidden</h1><hr /><p>"+fakename+"</p></body></html>");
            break;
          }
      }
          if (c == '\n') {
            // you're starting a new line
            currentLineIsBlank = true;
          }
          else if (c != '\r') {
            // you've gotten a character on the current line
            currentLineIsBlank = false;
          }
      }
      }
      // give the web browser time to receive the data
      delay(1);
      // close the connection:
      client.stop();
      Serial.println("client disconnected");
      
    }
}运行效果:




写在最后

C语言入门参考书推荐:C Primer Plus(中文版)

HTTP协议指南 : HTTP权威指南

某1o 发表于 2015-11-7 21:52

占楼 以后更新用

seesea 发表于 2015-11-7 23:02

虽然看不懂,不过知道很厉害!

卓泰科技 发表于 2015-11-15 20:34

不明觉厉

younger1513 发表于 2018-8-27 17:41

请问楼主,如果我把html文件和css文件放在sd卡里面打开时能否跳转到我我html中写的网页中去?能否实现用户通过网页控制arduino?
页: [1]
查看完整版本: Arduino+w5100使用String类 解析GET请求