Php 如何使我的Arduino仅从Web服务器读取特定字符?

Php 如何使我的Arduino仅从Web服务器读取特定字符?,php,arduino,arduino-uno,Php,Arduino,Arduino Uno,我刚刚开始网络编程&Arduino。我试图学习Arduino如何与Web服务器通信 我有一个Arduino UNO,它通过SimComm SIM808 GSM-GPRS模块与我的手机通信。我的Web服务器上有一个名为retrieve.php的文件,它基本上从数据库中获取数据并将数据发送给任何发出请求的人 我的Arduino程序正在读取该文件,但读取的内容超出了应有的范围 retrieve.php回显两个值1和1。你可以看看 问题是当我让我的Arduino调用这个文件时,它读取所有内容&这就是我最

我刚刚开始网络编程&Arduino。我试图学习Arduino如何与Web服务器通信

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

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

retrieve.php回显两个值1和1。你可以看看

问题是当我让我的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();
}
结果:

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

你的问题其实不是一个。您应该阅读更多关于HTTP协议规范的内容,以充分了解您的问题所在

当您的PHP脚本返回一些输出时,HTTP服务器将为其提供服务。您的客户机正在使用一个记录良好的协议与服务器通信,例如:

  • 客户→服务器:
  • 请把这个地址的页面给我

    GET www.boat.esy.es/retrieve.php HTTP/1.1
    
  • 服务器→客户:
  • 嘿,这里有一些关于你的请求的细节,然后是你的内容

    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("");
    
    这里,
    000D 000A
    分别是
    \r\n
    。因此,您应该在用
    ^^^^^^^^^^^^^^^^
    突出显示的相同位置找到
    000D 000A 000D 000A
    序列

    这将帮助您仔细检查服务器生成的字符串是否是使用
    strstr()
    进行解析时所需的字符串


    HTH

    我得到了与以前相同的输出。在这里更新了我的Arduino代码我只是修改了代码,因为我忘记在
    strstr()之后包含错误检查。请检查一下……如果它仍然不起作用,您应该尝试使用
    “\n\n”
    ,即使这不是标准要求的。对于您的问题,您应该让程序崩溃(尝试将空指针打印为字符串)或打印内容。它不应该显示数据…:-我再次更新了我的帖子。请查看更新1部分。我得到一些奇怪的输出。它在内容读取中显示
    错误,因为内容变量为null,但过了一段时间,它将打印msg变量的其余内容嘿!!!这个问题已经解决了。问题出在图书馆本身。图书馆。。与您提供的代码片段完美配合。。谢谢
    
    // 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.");
        }
    }
    
    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 
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     ^^^^ ^^^^ ^^^^ ^^^^