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

Arduino中文社区

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 17311|回复: 4

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

[复制链接]
发表于 2015-11-7 21:44 | 显示全部楼层 |阅读模式
本帖最后由 某1o 于 2015-11-7 22:35 编辑

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

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

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

在接收请求之前 我们需要了解一下HTTP请求的格式:
[mw_shl_code=c,true]GET /path/file?name=value HTTP/1.0换行符
HOST:  myarduino.ip换行符
[/mw_shl_code]
在这里 我们只需要接收一行请求,我们最终的目的是要获取GET 和HTTP中间的请求路径和表单信息

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


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

接下来进行字符串的切割(Arduino官网的Wiki讲的很详细 https://www.arduino.cc/en/Reference/StringObject 大家可以详细阅读一下)
[mw_shl_code=c,true]//判断字符串"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"));
            }[/mw_shl_code]

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


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


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


完整代码参考:
[mw_shl_code=c,true]#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");
      
    }
  }[/mw_shl_code]运行效果:
QQ截图20151107214258.png

QQ截图20151107214101.png

写在最后

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

HTTP协议指南 : HTTP权威指南
 楼主| 发表于 2015-11-7 21:52 | 显示全部楼层
占楼 以后更新用
发表于 2015-11-7 23:02 | 显示全部楼层
虽然看不懂,不过知道很厉害!
发表于 2018-8-27 17:41 | 显示全部楼层
请问楼主,如果我把html文件和css文件放在sd卡里面打开时能否跳转到我我html中写的网页中去?能否实现用户通过网页控制arduino?
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|Archiver|手机版|Arduino中文社区

GMT+8, 2024-11-28 00:42 , Processed in 0.129909 second(s), 18 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表