Чтение HTTP страницы ethernet shield enc28j60

rk9uba
Offline
Зарегистрирован: 12.01.2017

Здравствуйте!

Задача: считать страницу с сайта-сервера.

Работает связка Аруино мега+ethernet shield enc28j60. По ссылки арудинка проходит-всё ОК. А вот как считать страницу ни как не пойму. Есть какая нибудь спец функция для этого?


#include <EtherCard.h>

// ethernet interface mac address, must be unique on the LAN
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };

byte Ethernet::buffer[700];
static uint32_t timer;

const char website[] PROGMEM = "www.myserver.com";

// called when the client request is complete
static void my_callback (byte status, word off, word len) {
  Serial.println(">>>");
  Ethernet::buffer[off+300] = 0;
  Serial.print((const char*) Ethernet::buffer + off);
  Serial.println("...");
}

void setup () {
  Serial.begin(57600);
  Serial.println(F("\n[webClient]"));

  // Change 'SS' to your Slave Select pin, if you arn't using the default pin
  if (ether.begin(sizeof Ethernet::buffer, mymac, SS) == 0)
    Serial.println(F("Failed to access Ethernet controller"));
  if (!ether.dhcpSetup())
    Serial.println(F("DHCP failed"));

  ether.printIp("IP:  ", ether.myip);
  ether.printIp("GW:  ", ether.gwip);
  ether.printIp("DNS: ", ether.dnsip);

#if 1
  // use DNS to resolve the website's IP address
  if (!ether.dnsLookup(website))
    Serial.println("DNS failed");
#elif 2
  // if website is a string containing an IP address instead of a domain name,
  // then use it directly. Note: the string can not be in PROGMEM.
  char websiteIP[] = "192.168.1.1";
  ether.parseIp(ether.hisip, websiteIP);
#else
  // or provide a numeric IP address instead of a string
  byte hisip[] = { 192,168,1,1 };
  ether.copyIp(ether.hisip, hisip);
#endif

  ether.printIp("SRV: ", ether.hisip);
}

void loop () {
  ether.packetLoop(ether.packetReceive());

  if (millis() > timer) {
    timer = millis() + 5000;
    Serial.println();
    Serial.print("<<< REQ ");
    ether.browseUrl(PSTR("/foo/"), "bar", website, my_callback);
  }
}

 

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

А памяти на страницу точно хватить?

rk9uba
Offline
Зарегистрирован: 12.01.2017

Там страница 20 символов

sadman41
Offline
Зарегистрирован: 19.10.2016

Перейдите на UIPEthernet и возьмите за основу пример WebClient от стандартного Ethernet.h

rk9uba
Offline
Зарегистрирован: 12.01.2017

 

IPAddress ip(192, 168, 0, 177);

// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
EthernetClient client;

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // start the Ethernet connection:
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // try to congifure using IP address instead of DHCP:
    Ethernet.begin(mac, ip);
  }
  // give the Ethernet shield a second to initialize:
  delay(1000);
  Serial.println("connecting...");

  // if you get a connection, report back via serial:
  if (client.connect(server, 80)) {
    Serial.println("connected");
    // Make a HTTP request:
    client.println("GET /get.php?login=Loke");
    client.println("Host: www.tabloseller.ru");
    client.println("Connection: close");
    client.println();
  } else {
    // if you didn't get a connection to the server:
    Serial.println("connection failed");
  }
}

void loop() {
  // if there are incoming bytes available
  // from the server, read them and print them:
  if (client.available()) {
    char c = client.read();
    Serial.print(c);
  }

  // if the server's disconnected, stop the client:
  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();

    // do nothing forevermore:
    while (true);
  }
}

ОТВЕТ

connecting...
connected
HTTP/1.1 200 OK
Date: Wed, 26 Sep 2018 05:15:52 GMT
Content-Type: text/html;charset=UTF-8
Content-Length: 0
Server: Jino.ru/mod_pizza
Vary: Accept-Encoding
X-Cache: MISS from venus
X-Cache-Lookup: MISS from venus:0
Via: 1.1 venus (squid/3.3.8)
Connection: close
 
 
disconnecting.
 
ОТВЕТ такой же как и раньше. Страницу не могу прочитать
sadman41
Offline
Зарегистрирован: 19.10.2016

Ну, а какой-нибудь там yandex.ru читает?

rk9uba
Offline
Зарегистрирован: 12.01.2017

Спасибо все заработало! Была проблема в ссылке!

connecting...
connected
HTTP/1.1 200 OK
Date: Wed, 26 Sep 2018 05:37:03 GMT
Content-Type: text/html;charset=UTF-8
Content-Length: 18
Server: Jino.ru/mod_pizza
Vary: Accept-Encoding
X-Cache: MISS from venus
X-Cache-Lookup: MISS from venus:0
Via: 1.1 venus (squid/3.3.8)
Connection: close
 
1000|100|1111|1111        ---МОЯ ЗАПИСЬ!
disconnecting.
 
rk9uba
Offline
Зарегистрирован: 12.01.2017

Вопрос другого плана:

Как считать именно запись-можно ли выкинуть шапку?

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Что значит "выкинуть"?

Если она Вам не нужна, просто не нужно ее сохранять.

rk9uba
Offline
Зарегистрирован: 12.01.2017

Как ее не сохранять? 

b707
Offline
Зарегистрирован: 26.05.2017

rk9uba пишет:

Как ее не сохранять? 

например, встроить в начало своих данных уникальный маркер:

RK9uba: 1000|100|1111|1111

и пропускать все строчки ответа, не начинающиеся с "RK9uba:"

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

rk9uba пишет:

Как ее не сохранять? 

использовать циклический буфер.

читать литературу по словам - "алгоритм поиска по тексту / поиск ключевых слов".

например:


byte findCmdFromBuf(char* textCmd) {
  if (cmd_buf[pos_cmd] > 0) {
    byte idxBuf;
    if (pos_cmd == 0) idxBuf = max_size_cmd - 1; else idxBuf = pos_cmd - 1;
    byte lenResp = strlen(textCmd);
    byte idxResp = lenResp - 1;
    byte cntResp = 0;
    for (byte i = 0; i < max_size_cmd; ++i) {
      if (cmd_buf[idxBuf] == 0) break;
      if (cmd_buf[idxBuf] == textCmd[idxResp]) {
        --idxResp;
        if ((++cntResp) == lenResp) return 1;
      } else {
        cntResp = 0; idxResp = lenResp - 1;
      }
      if ((--idxBuf) == 0) idxBuf = max_size_cmd - 1;
    }
  } else if (pos_cmd > 0) {
    if (strPos(cmd_buf, textCmd) >= 0) {
      return 1;
    }
  }
  return 0;
}


char* LastPos(char *str1, char *str2) { // find substring in string
  int L1 = strlen(str1);
  int L2 = strlen(str2);
  for (int i = L1 - L2; i >= 0; i--)
  {
    int j = 0;
    for (; j < L2; j++)
      if ((str1[i + j] != str2[j]))
        break;
    if (j == L2)
      return str1 + i;
  }
  return 0;
}

int strPos(char *str11, char *str22) { // find position in string(1) substring(2)
  char*p = LastPos(str11, str22);
  int n = p - str11;
  return n;
}

 

rk9uba
Offline
Зарегистрирован: 12.01.2017
 // from the server, read them and print them:
  if (client.available()) {
    c = client.read();

  if(c=='$')
  {
   w=1; 
    }
    if(w==1)
    {

          
  Serial.print(c);
    }
  }

Вставил спецсимвол в свою строку $ и по нему делаю распознование. Всем спасибо!

sadman41
Offline
Зарегистрирован: 19.10.2016

Лучше \n\n ловить. В куках может $ прилететь за нефиг делать.

Logik
Онлайн
Зарегистрирован: 05.08.2014

rk9uba пишет:

 // from the server, read them and print them:
  if (client.available()) {
    c = client.read();

  if(c=='$')
  {
   w=1; 
    }
    if(w==1)
    {

          
  Serial.print(c);
    }
  }

Вставил спецсимвол в свою строку $ и по нему делаю распознование. Всем спасибо!

Явный претендент на звание самого кривого костыля года. Про CRLF два раза в конце хедера не слышал?

b707
Offline
Зарегистрирован: 26.05.2017

Logik пишет:

Явный претендент на звание самого кривого костыля года. Про CRLF два раза в конце хедера не слышал?

не соглашусь. "CRLF два раза в конце хедера" -это отлично, пока на странице только нужные данные. Но согласитесь, что так бывает крайне редко, а на коммерческих серверах - так вообще никогда.

А если все равно искать на странице нужное - то уникальный маркер в начале строки - это решение.

Хотя согласен, что символ '$' - плохой выбор.

Logik
Онлайн
Зарегистрирован: 05.08.2014

Разницу между хедером и страницей b707 ниосилил. Жаль. Ну и ладно ;)

b707
Offline
Зарегистрирован: 26.05.2017

Logik пишет:

Разницу между хедером и страницей b707 ниосилил. Жаль. Ну и ладно ;)

из чего вы сделали такой вывод?

Наоборот, мне со своей стороны кажется. что это Logic недопонял тот текст, на который пытался отвечать :)

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Товарищи, еще же не пятница...

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Logik пишет:

Разницу между хедером и страницей b707 ниосилил. Жаль. Ну и ладно ;)

ну-ка ну-ка расскажите , очень любопытно что такое хедер и страница? :)

а то мне вот сервер строчку выдает "INFO INSERT!" - не пойму где что находиться :(

 

b707
Offline
Зарегистрирован: 26.05.2017

sadman41 пишет:

Товарищи, еще же не пятница...

Садман, не переживай, я понимаю, с кем спорю и далеко не пойду :)

b707
Offline
Зарегистрирован: 26.05.2017

andycat пишет:

а то мне вот сервер строчку выдает "INFO INSERT!" - не пойму где что находиться :(

 

скорее всего вы смотрите ответ программой, которая скрывает от вас "ненужные детали". Дума, что полный ответ что-то типа этого:

HTTP/1.1 200 OK
Date: Wed, 26 Sep 2018 05:37:03 GMT
Content-Type: text/html;charset=UTF-8
Content-Length: 18
Server: Jino.ru/mod_pizza
Vary: Accept-Encoding
X-Cache: MISS from venus
X-Cache-Lookup: MISS from venus:0
Via: 1.1 venus (squid/3.3.8)
 
INFO INSERT!
andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Я смотрю ответ командой httpread на модеме sim800, а отсылаю на php сервере командой echo без всяких заголовков и прочего.
ЗЫ. Допускаю что я чего то не понимаю и или чего-то не знаю.

b707
Offline
Зарегистрирован: 26.05.2017

andycat пишет:
Я смотрю ответ командой httpread на модеме sim800, .

краткий поиск по гуглю выдал ответ - команда HTTPREAD выдает только тело (httpbody) HTML странички, скрывая от вас хидер - как я и предполагал. Хотя тоже не исключаю, что в своем кратком поиске что-то недосмотрел.

это внутренняя команда модемов SIMxxx

sadman41
Offline
Зарегистрирован: 19.10.2016

echo() в php пишет в body. В хидер информация засовывается через функцию header().

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

да, был не прав, просто не вижу заголовок.

Logik
Онлайн
Зарегистрирован: 05.08.2014

Так чё, уже разобрались пока я отобедал? На всяк случай - согласно стандарту протокола HTTP ответ состоит из хедера (набора строк вида имя параметра:значение), названого ТС "шапка"   и тела - "страницы" в местной терминологии, хотя вобщето там могут быть очень разнообразные данные.  Строки хедера завершаются CRLF.  Хедер завершается пустой строкой, следовательно имеем два подряд CRLF. Это и отделяет хедер от данных. Этим и пользоватся. Остальное - х-ня от безмозглых. Хотябы потому, что прилететь от сервера может и Content-Type: отличный от text/html; и в нем уже будут и "$" и "RK9uba:", что вызовет ошибку. И в составе хедера значения параметров могут совпасть. А вот уже в данных можна уже делать как душе угодно, но помнить про Content-Type. Конкретно ТС очевидно для его бинарных данных как бы логично использовать application/octet-stream.

Просто игнорить хедер - нехороше, надо бы хотяб удостоверится в том что ОК, что длина данных не ноль, что тип ожидаемый.

b707
Offline
Зарегистрирован: 26.05.2017

Logik пишет:

Просто игнорить хедер - нехороше, надо бы хотяб удостоверится в том что ОК, что длина данных не ноль, что тип ожидаемый.

с этим не спорю

Logik
Онлайн
Зарегистрирован: 05.08.2014

а с чем спорите?

 

b707
Offline
Зарегистрирован: 26.05.2017

Logik пишет:

а с чем спорите?

с безаппеляционным "только CRLF и ничего более, остальное от безмозглых". Но я даже не спорю... просто не согласен, затевать флейм неохота :)

Logik
Онлайн
Зарегистрирован: 05.08.2014

;)

 

Logik
Онлайн
Зарегистрирован: 05.08.2014

Вся возня с хедером на самом деле очень не сложна, чтото типа

  if (Serial.available()) 
  {
    c = Serial.read();
    
    if(c==0x0d)      fl|=1; 
    else if(c!=0x0a)  fl=0;
    else
    {
      if(fl==1)
      { 
        fl<=1;
        buf[p]=0;
      //пришло CRLF разбор строки в буфере
        p=0;
      }
      else if(fl==3)
      {
        //пришло два CRLF, весь хедер пришел дальше тело принимаем
      }
    }
    
    if(p<sizeof(buf))
    {
      buf[p]=c;
      p++;
    }
  }

Драл из старого проекта, там по сириалу бегало, вроде работало.

b707
Offline
Зарегистрирован: 26.05.2017

Logik пишет:

Вся возня с хедером на самом деле очень не сложна, чтото типа

да это все понятно.

Но вспомните статью, что мы недавно обсуждали в теме "Субботнее". "Пустая" страница фейсбука весит толи 1.5, толи 15 мегабайт. И чтобы найти на такой "пустой" странице свои 10 байт данных - мало отбросить хидер, хорошо бы иметь уникальную строчку, по которой мы сможем найти данные в этой куче Г, которым является современный HTML