本帖最后由 某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]运行效果:
写在最后
C语言入门参考书推荐:C Primer Plus(中文版)
HTTP协议指南 : HTTP权威指南
|