如何让我的Arduino只读取Web服务器中的特定字符?

时间:2016-06-04 15:14:44

标签: php arduino arduino-uno

我刚刚开始使用Web Programming& Arduino的。我正在尝试学习Arduino如何与Web服务器通信。

我有这个Arduino UNO通过 SimComm SIM808 GSM-GPRS 模块与我的Web Server通信。我的Web服务器上有一个名为 retrieve.php 的文件,它基本上从数据库和数据库中提取数据。将它们发送给提出请求的人。

我的Arduino程序正在读取文件,但它读取的内容超出了应有的范围。

retrieve.php 回显两个值1&你可以看一下here

问题是,当我让我的Arduino调用此文件时,它会读取所有内容。这就是我最终得到的

GSM Shield testing.

status=READY
status=ATTACHED

100.107.219.185
H
Number of data received:
1

Data received:
H
TTP/1.1 200 OK
Date: Sat, 04 Jun 2016 13:07:05 GMT
Server: Apache
X-Powered-By: PHP/5.5.35
Content-Length: 2
Connection: close
Content-Type: text/html

11
CLOSED

我的 Arduino 代码如下: -

#include "SIM900.h"
#include <SoftwareSerial.h>
#include "inetGSM.h"
//#include "sms.h"
//#include "call.h"

//To change pins for Software Serial, use the two lines in GSM.cpp.

//GSM Shield for Arduino
//www.open-electronics.org
//this code is based on the example of Arduino Labs.

//Simple sketch to start a connection as client.

InetGSM inet;
//CallGSM call;
//SMSGSM sms;

char msg[50];
int numdata;
char inSerial[50];
int i=0;
boolean started=false;

void setup()
{
     //Serial connection.
     Serial.begin(9600);
     Serial.println("GSM Shield testing.");
     //Start configuration of shield with baudrate.
     //For http uses is raccomanded to use 4800 or slower.
     if (gsm.begin(2400)) {
          Serial.println("\nstatus=READY");
          started=true;
     } else Serial.println("\nstatus=IDLE");

     if(started) {
          //GPRS attach, put in order APN, username and password.
          //If no needed auth let them blank.
          if (inet.attachGPRS("TATA.DOCOMO.INTERNET", "", ""))
               Serial.println("status=ATTACHED");
          else Serial.println("status=ERROR");
          delay(1000);

          //Read IP address.
          gsm.SimpleWriteln("AT+CIFSR");
          delay(5000);
          //Read until serial buffer is empty.
          gsm.WhileSimpleRead();

          //TCP Client GET, send a GET request to the server and
          //save the reply.
          numdata=inet.httpGET("www.boat.esy.es", 80, "/retrieve.php", msg, 1);
          //Print the results.
          Serial.println("\nNumber of data received:");
          Serial.println(numdata);
          Serial.println("\nData received:");
          //Serial.println(msg);

          char* content = strstr(msg,"\r\n\r\n");
          content = content+4;
          Serial.println(content);
     }
};

void loop()
{
     //Read for new byte on serial hardware,
     //and write them on NewSoftSerial.
     serialhwread();
     //Read for new byte on NewSoftSerial.
     serialswread();
};

void serialhwread()
{
     i=0;
     if (Serial.available() > 0) {
          while (Serial.available() > 0) {
               inSerial[i]=(Serial.read());
               delay(10);
               i++;
          }

          inSerial[i]='\0';
          if(!strcmp(inSerial,"/END")) {
               Serial.println("_");
               inSerial[0]=0x1a;
               inSerial[1]='\0';
               gsm.SimpleWriteln(inSerial);
          }
          //Send a saved AT command using serial port.
          if(!strcmp(inSerial,"TEST")) {
               Serial.println("SIGNAL QUALITY");
               gsm.SimpleWriteln("AT+CSQ");
          }
          //Read last message saved.
          if(!strcmp(inSerial,"MSG")) {
               Serial.println(msg);
          } else {
               Serial.println(inSerial);
               gsm.SimpleWriteln(inSerial);
          }
          inSerial[0]='\0';
     }
}

void serialswread()
{
     gsm.SimpleRead();
}

这是我的 PHP 代码

<?php 

    $server = "mysql.hostinger.in";
    $user = "xxxxxxxxxx";
    $password = "xxxxxx";
    $db = "xxxxxxx";

    $lck;
    $ign;

    $conn = mysqli_connect($server,$user,$password,$db);

    if($conn->connect_error)
    {
        die("Connection Failed:" . $conn->connect_error);
    }

    $query = "SELECT unlck_lck, ignition FROM BOATOP";
    $res = $conn->query($query);

    if($res->num_rows>0)
    {
        $row = $res->fetch_assoc();
        $lck = $row["unlck_lck"];
        $ign = $row["ignition"];

        echo $lck;
        echo $ign;
    }

    mysqli_close($conn);


?>

我希望我的Arduino只读取我的PHP文件回显的输出。但目前正在阅读所有内容。

我还需要在这里提一件事。对于我的Arduino GSM Shield,我没有使用Arduino安装包附带的示例或库,因为这些库与我的GSM Shield不兼容。相反,我使用了一些我在网上找到的库。我没有在这里发布这些文件,因为它们会使我的帖子真的很长。如果您需要查看它们,请告诉我。

更新1

内容显示为空

Arduino修改

content = strstr(msg,"\r\n\r\n");
if(content == NULL) {
    Serial.println("ERROR IN CONTENT READING");
} else {
    content = content + 4;
    Serial.println("The Content Is:");
    Serial.println(content);
}

结果:

GSM Shield testing.

status=READY
status=ATTACHED

100.110.244.218

Number of data received:
50

Data received:

ERROR IN CONTENT READING
HTTP/1.1 200 OK
Date: Sat, 04 Jun 2016 17:17:12 GMT
Server: Apache
X-Powered-By: PHP/5.5.35
Content-Length: 2
Connection: close
Content-Type: text/html

11
CLOSED

1 个答案:

答案 0 :(得分:2)

您的问题实际上不是一个问题。您应该阅读有关HTTP协议规范的更多信息,以完全了解您的问题。

当您的PHP脚本返回一些输出时,它将由HTTP服务器提供服务。您的客户端正在与服务器进行通信,其中包含一个记录良好的协议,例如:

  1. 客户端→服务器:
  2. 请在这个地址给我页面!

    GET www.boat.esy.es/retrieve.php HTTP/1.1
    
    1. 服务器→客户端:
    2. 嘿,这里有一些关于您的请求的详细信息,然后是您的内容

      HTTP/1.1 200 OK
      Date: Sat, 04 Jun 2016 13:07:05 GMT
      Server: Apache
      X-Powered-By: PHP/5.5.35
      Content-Length: 2
      Connection: close
      Content-Type: text/html
      
      11
      

      给出的上下文通常可以帮助您的webbrowser更好地处理您的数据。但是在嵌入式环境中它也可以帮助你。例如,如果Content-Length对于您的变量而言太大,您可以检测到并显示一个错误,您无法将这么多数据保存到内存中!

      因此,作为arduino代码中的一个简单解决方案,您需要读取Web服务器的输出,丢弃它输出的每一行,直到它达到\r\n\r\n,在HTTP协议中它是标题和内容之间的分隔符。然后,所有以下数据都将是您的PHP代码输出的内容。

      这样做的方法是:

      numdata=inet.httpGET("www.boat.esy.es", 80, "/retrieve.php", msg, 1);
      // look up substring '\r\n\r\n' within msg, and allocate content with it
      char * content = strstr(msg, "\r\n\r\n");
      if (content == NULL) {
          Serial.println("Couldn't find the contents within the message!");
      } else {
          // then we skip the '\r\n\r\n' substring to only keep the contents
          content = content+4; // we skip 4 characters
          Serial.print("The content is: ");
          Serial.println(content);
      }
      

      如果您尝试提取内容长度标题,则可以执行相同的操作:

      // lookup the content-length header
      char* content = strstr(msg, "Content-Length: ");
      // skip the size of the looked up string
      content = content+strlen("Content-Length: ");
      // store the size of the contents in number of characters
      int nb_chars = atoi(content);
      // lookup the content
      content = strstr(msg, "\r\n\r\n");
      // check that the substring has been found
      if (content == NULL) {
          Serial.println("Couldn't find the contents within the message!");
      } else {
          // skip the header-content delimiter
          content = content+4;
          // and do useful things with the extracted data
          if (nb_chars == 2) {
              Serial.print("The content is:");
              Serial.println(content);
          } else {
              Serial.println("There's been an error processing the request.");
          }
      }
      

      你会在那里找到一个正在运行的代码版本:

      作为测试,您可能需要打印字符串中每个字符的ASCII代码进行测试,以代替原始Serial.println(msg)尝试:

      for (int c=0; c<strlen(msg); ++c) {
          Serial.print((int)msg[c], HEX);
          Serial.print(" ");
      }
      Serial.println("");
      

      应产生以下输出:

      0048 0054 0054 0050 002F 0031 002E 0031 0020 0032 0030 0030 0020 004F 004B 000D 000A 0044 0061 0074 0065 003A 0020 0053 0061 0074 002C 0020 0030 0034 0020 004A 0075 006E 0020 0032 0030 0031 0036 0020 0031 0033 003A 0030 0037 003A 0030 0035 0020 0047 004D 0054 000D 000A 0053 0065 0072 0076 0065 0072 003A 0020 0041 0070 0061 0063 0068 0065 000D 000A 0058 002D 0050 006F 0077 0065 0072 0065 0064 002D 0042 0079 003A 0020 0050 0048 0050 002F 0035 002E 0035 002E 0033 0035 000D 000A 0043 006F 006E 0074 0065 006E 0074 002D 004C 0065 006E 0067 0074 0068 003A 0020 0032 000D 000A 0043 006F 006E 006E 0065 0063 0074 0069 006F 006E 003A 0020 0063 006C 006F 0073 0065 000D 000A 0043 006F 006E 0074 0065 006E 0074 002D 0054 0079 0070 0065 003A 0020 0074 0065 0078 0074 002F 0068 0074 006D 006C 000D 000A 000D 000A 0031 0031 000D 000A 
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       ^^^^ ^^^^ ^^^^ ^^^^
      

      此处,000D 000A分别为\r\n。因此,您应该在与000D 000A 000D 000A突出显示的位置相同的位置找到^^^^ ^^^^ ^^^^ ^^^^序列。

      这应该可以帮助您仔细检查服务器生成的字符串是否是我们在使用strstr()进行语法分析时所期望的字符串。

      HTH