GETrequest slow

Discussions related to the WiServer add-on code for WiShield. WiServer is a friendly, easy-to-use front end for webserver and webclient usages.

Moderator: shard7

GETrequest slow

Postby burntcrispy » Fri Feb 26, 2010 3:27 pm

GETrequest seem to be slow, taking an average of 7 seconds, before you can send another one (or serve a web page after). Yet it only takes around a second to finish with the ReturnFunc and End a connection (debug info); What does it do for the around 6 second delay until it will send another.

Even the 1 second to get a reply is still quite a bit slower than it takes from another computer, <200ms, or even the time for the wiShield to serve a simple web page, <500ms, I would expect a GETrequest sent from the wiShield to be quicker then assembling and sending an web page as it a get request is already assembled ahead of time.

It looks like the wiShield waits more than half a second before even sending the request.

I was going to use this as a input to trigger lights on my Ethernet bridged Home Automation system, but these times hurt, the Automation protocol already puts in too much delay, and for this implementation I need it to be quick as possible, any suggestions?

Thanks,
burntcrispy
 
Posts: 4
Joined: Mon Jan 11, 2010 8:20 am

Re: GETrequest slow

Postby shard7 » Sat Feb 27, 2010 6:02 am

WiServer should be able to run much faster than that. A few things to check:

Do you have any other activity occurring simultaneously with the WiServer such as another computer requesting a web page? If so, it may be that the GET request has to wait for a connection to become available. By default the IP stack is built to support just one connection at a time to save memory, and if one request is using the connection, any others have to wait until it is closed before they can proceed. You can increase the number of connections using a #define in the uIP stack code, but that does require additional RAM.

The other obvious thing to check is the quality of the wireless connection, since transmission errors and lost packets will result in retries until the data is sent or received successfully.

One final thing, be sure to call the WiServer's server_task() function frequently. A singe request may require several task cycles to complete, so if possible this function should be as often as possible (e.g. a few hundred times a second). If other work is being done for a second or so between these calls, WiServer performance will be quite slow.

Hope this helps. If you still have issues, please post your sketch code.

Mark
shard7
 
Posts: 64
Joined: Wed May 06, 2009 11:30 am

Re: GETrequest slow

Postby burntcrispy » Sat Feb 27, 2010 4:04 pm

Thanks Mark,

There shouldn't be any other activity with the wiShield, and little else for traffic going on.

I have tried two access-points, same result, the one I am using currently is less than 10 foot away.

I removed the Server portion of my code and some other un-needed code, with the same results as earlier.

My code checks analog pin 0, as a digital input (14), and calls two different get Requests, one when it changes to high, one when to low, and times how long it takes to call the printData function.

Code: Select all
/*
* A simple sketch that uses WiServer to get the hourly weather data from LAX and prints
* it via the Serial API
*/

#include <WiServer.h>

#define WIRELESS_MODE_INFRA   1
#define WIRELESS_MODE_ADHOC   2

// Wireless configuration parameters ----------------------------------------
unsigned char local_ip[] = {192,168,0,237};   // IP address of WiShield
unsigned char gateway_ip[] = {192,168,0,123};   // router or gateway IP address
unsigned char subnet_mask[] = {255,255,255,0};   // subnet mask for the local network
const prog_char ssid[] PROGMEM = {"pinky"};      // max 32 bytes

unsigned char security_type = 0;   // 0 - open; 1 - WEP; 2 - WPA; 3 - WPA2

// WPA/WPA2 passphrase
const prog_char security_passphrase[] PROGMEM = {"12345678"};   // max 64 characters

// WEP 128-bit keys
// sample HEX keys
prog_uchar wep_keys[] PROGMEM = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,   // Key 0
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   // Key 1
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   // Key 2
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00   // Key 3
            };

// setup the wireless mode
// infrastructure - connect to AP
// adhoc - connect to another WiFi device
unsigned char wireless_mode = WIRELESS_MODE_INFRA;

unsigned char ssid_len;
unsigned char security_passphrase_len;
// End of wireless configuration parameters ----------------------------------------

long time = 0;

// Function that prints data from the server
void printData(char* data, int len) {
 
  // Print the data returned by the server
  // Note that the data is not null-terminated, may be broken up into smaller packets, and
  // includes the HTTP header.
  Serial.print("\n\r Time=");
  Serial.print((millis()-time));
  Serial.print("\n\r");
  /*
  while (len-- > 0) {
    Serial.print(*(data++));
  }
  */
}


uint8 ip[] = {192,168,0,239};
//char auth[] = WiServer.base64encode("admin:admin"); // Base64 encoded USERNAME:PASSWORD
char auth[] = "YWRtaW46YWRtaW4=";

// A request to ISY
GETrequest high(ip, 80, "192.168.0.239", "/rest/nodes/E%2084%205A%201/cmd/DOF");
GETrequest low(ip, 80, "192.168.0.239", "/rest/nodes/E%2084%205A%201/cmd/DON");

void setup() {
    // Initialize WiServer (we'll pass NULL for the page serving function since we don't need to serve web pages)
  WiServer.init(NULL);
 
  // Enable Serial output and ask WiServer to generate log messages (optional)
  Serial.begin(9600);
  WiServer.enableVerboseMode(true);

  // Have the processData function called when data is returned by the server
  high.setReturnFunc(printData);
  high.setAuth(auth);
  low.setReturnFunc(printData);
  low.setAuth(auth);
  digitalWrite(14,HIGH);//Turns on Analog's 0 pull up resistor

}


//Stores pins previous value
int previous = digitalRead(14);
void loop(){

  int current = digitalRead(14);
  if (current != previous)//Check to see if pin state has changed
  {
    if (current == HIGH)
    {
      time = millis();
      high.submit();
      Serial.print("High\r\n");
    }
    else if (current == LOW)
    {
      time = millis();
      low.submit();
      Serial.print("Low\r\n");
    }   
    previous = digitalRead(14);//Set current state to compare to in next loop
  } 

  // Run WiServer
  WiServer.server_task();

  //delay(10);
}


Thanks,
burntcrispy
 
Posts: 4
Joined: Mon Jan 11, 2010 8:20 am

Re: GETrequest slow

Postby shard7 » Sun Feb 28, 2010 12:55 pm

I don't see anything obvious that would cause the delays. Let me think about it and double check the WiServer code in case your sketch is creating a situation that I hadn't considered before. You may also want to open up the source code for WiServer and add some additional debug statements specifically related to the timing of connections and rx/tx events.

I did notice one minor issue in your main loop: instead of calling digitalRead(14) a second time to update the value of 'previous', try setting it to the value of 'current' instead. If the signal on pin 14 has any sort of noise or oscillation, the second reading on the pin may be different and thus might cause the submit calls to happen several times in a short period of time. This change will also ensure that you don't miss a transition that occurs between the two readings.

Mark
shard7
 
Posts: 64
Joined: Wed May 06, 2009 11:30 am

Re: GETrequest slow

Postby GregEigsti » Mon Mar 01, 2010 10:32 pm

Two completely random ideas ;)
  • Maybe Wireshark, or equivalent, could help better characterize the problem (or show if there is some retry flood badness going on).
  • shard7 does WiServer take advantage of "polling" in the UIP_APPCALL callback (sorry don't remember and am feeling lazy at the moment)? If so decreasing the poll time would most likely have dramatic affects.
How stable is the value that you read from digitalRead(14)? If it changes often you could be calling submit really often and gumming things up. Dunno. Maybe some data smoothing or thresholds might help with this. Not sure if its an issue as I missed what you are doing on pin 14 ;)

my Ethernet bridged Home Automation system

What equipment are you using?

Greg
Check out the wiki!
uIP Stack Docs
Compatible Access Point List
WiShield user contrib branch - DNS, DHCP, AP Scanning, bug fixes, etc.
SlackLab.org - My geek projects blog.
User avatar
GregEigsti
 
Posts: 1067
Joined: Sun Aug 02, 2009 5:23 pm
Location: Sammamish WA USA (near Seattle)
  • Website

Re: GETrequest slow

Postby burntcrispy » Tue Mar 02, 2010 9:23 am

Pin 14 is very stable, using the internal pull-up resistor, it only changes when I change it manually by adding or removing a jumper to ground.

I am using the Insteon protocol, http://www.insteon.net/, with Universal Device's ISY, http://www.universal-devices.com/99i.htm, to access it through Ethernet.

I seem to have two time problems:
1. The time it takes to send the command, hard to time, but it takes around a second to get a reply.
2. After receiving the reply and closing the socket, it delays another 6 seconds or so until I can send another; Increasing the number of connections makes this less noticeable. (Thanks Mark!)

Thanks,
burntcrispy
 
Posts: 4
Joined: Mon Jan 11, 2010 8:20 am

Re: GETrequest slow

Postby GregEigsti » Tue Mar 02, 2010 12:24 pm

Insteon is good stuff! Have wondered about forcing the Arduino USB into host most to control an Insteon USB controller to achieve a WiFi bridge to my Insteon gear.

Greg
Check out the wiki!
uIP Stack Docs
Compatible Access Point List
WiShield user contrib branch - DNS, DHCP, AP Scanning, bug fixes, etc.
SlackLab.org - My geek projects blog.
User avatar
GregEigsti
 
Posts: 1067
Joined: Sun Aug 02, 2009 5:23 pm
Location: Sammamish WA USA (near Seattle)
  • Website

Re: GETrequest slow

Postby shard7 » Sat Mar 06, 2010 6:50 am

I took a look at the WiServer code, and for received data it's driven by the uIP callback, which in turn is triggered by calling server_task. As long as the server task is called frequently, this should be fine.

Given that additional connections alleviated the problem, I suspect the issue is that the server machine isn't closing the connection after sending the response, and so the connection is tied up until it times out and other requests have to wait. Right now WiServer doesn't examine the response header for a data length, and so it relies on the connection closing to indicate the end of the data (which is acceptable per HTTP 1.0).

For HTTP 1.0 the default behavior is to close connections after each response unless the 'keep alive' option is explicitly set in the request, but it's very possible that some servers out there just default to HTTP 1.1 behavior and keep it open anyway. It may be worthwhile to look into this and maybe add a little extra debug code in WiServer.cpp to indicate when the connection is closed vs. times out.

Mark
shard7
 
Posts: 64
Joined: Wed May 06, 2009 11:30 am

Re: GETrequest slow

Postby mkarau » Fri Jun 04, 2010 7:29 am

Not being expert on either the inner workings of uIP or HTTP 1.0/1.1, I can't say that the following is a "proper solution", but it fixes the long (7 seconds) delays experienced by many when trying to communicate with an HTTP/1.1 server for GET/POST requests.

In the example "SimpleClient", add to the following line to the bottom of the returnFunction "printData":
Code: Select all
uip_close();


This tells uIP to nicely close the connection (Something an HTTP/1.1 server doesn't want to do automatically). The result, in my case, is that GET/POST requests can be safely issued at a rate of 1 per second instead of 1 per seven seconds. (I never imagined considering 1 request per second to be FAST, but such are the joys of an 8-bit player in a >32-bit world.)

Entire Example (Replace network settings with your own):
Code: Select all
/*
* A simple sketch that uses WiServer to get the hourly weather data from LAX and prints
* it via the Serial API
*/

#include <WiServer.h>

#define WIRELESS_MODE_INFRA   1
#define WIRELESS_MODE_ADHOC   2

// Wireless configuration parameters ----------------------------------------
unsigned char local_ip[] = {192,168,1,2};   // IP address of WiShield
unsigned char gateway_ip[] = {192,168,1,1};   // router or gateway IP address
unsigned char subnet_mask[] = {255,255,255,0};   // subnet mask for the local network
const prog_char ssid[] PROGMEM = {"ASYNCLABS"};      // max 32 bytes

unsigned char security_type = 0;   // 0 - open; 1 - WEP; 2 - WPA; 3 - WPA2

// WPA/WPA2 passphrase
const prog_char security_passphrase[] PROGMEM = {"12345678"};   // max 64 characters

// WEP 128-bit keys
// sample HEX keys
prog_uchar wep_keys[] PROGMEM = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,   // Key 0
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   // Key 1
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   // Key 2
              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00   // Key 3
            };

// setup the wireless mode
// infrastructure - connect to AP
// adhoc - connect to another WiFi device
unsigned char wireless_mode = WIRELESS_MODE_INFRA;

unsigned char ssid_len;
unsigned char security_passphrase_len;
// End of wireless configuration parameters ----------------------------------------


// Function that prints data from the server
void printData(char* data, int len) {
 
  // Print the data returned by the server
  // Note that the data is not null-terminated, may be broken up into smaller packets, and
  // includes the HTTP header.
  while (len-- > 0) {
    Serial.print(*(data++));
  }
  uip_close();
}


// IP Address for www.weather.gov 
uint8 ip[] = {140,90,113,200};

// A request that gets the latest METAR weather data for LAX
GETrequest getWeather(ip, 80, "www.weather.gov", "/data/METAR/KLAX.1.txt");


void setup() {
    // Initialize WiServer (we'll pass NULL for the page serving function since we don't need to serve web pages)
  WiServer.init(NULL);
 
  // Enable Serial output and ask WiServer to generate log messages (optional)
  Serial.begin(57600);
  WiServer.enableVerboseMode(true);

  // Have the processData function called when data is returned by the server
  getWeather.setReturnFunc(printData);
}


// Time (in millis) when the data should be retrieved
long updateTime = 0;

void loop(){

  // Check if it's time to get an update
  if (millis() >= updateTime) {
    getWeather.submit();   
    // Get another update one hour from now
    updateTime += 1000 * 60 * 60;
  }
 
  // Run WiServer
  WiServer.server_task();

  delay(10);
}
mkarau
 
Posts: 1
Joined: Fri Jun 04, 2010 6:55 am

Re: GETrequest slow

Postby GregEigsti » Fri Jun 04, 2010 1:46 pm

Nice contribution mkarau; thanks!

Greg
Check out the wiki!
uIP Stack Docs
Compatible Access Point List
WiShield user contrib branch - DNS, DHCP, AP Scanning, bug fixes, etc.
SlackLab.org - My geek projects blog.
User avatar
GregEigsti
 
Posts: 1067
Joined: Sun Aug 02, 2009 5:23 pm
Location: Sammamish WA USA (near Seattle)
  • Website

Next

Return to WiServer

Who is online

Users browsing this forum: Yahoo [Bot] and 1 guest