Offline
Jr. Member
Karma: 0
Posts: 54
|
 |
« on: October 05, 2011, 09:14:47 pm » |
I dont know if I am doing this right, i have looked through many examples on how to do this but it still is not working for me. Basically I have a php script on a server that is programmed to update a sql database The script works when someone goes to the webpage: http://cs14.sheridanc.on.ca/connect.php?var1=x&var2=x(where x is a value to be written to the database) it works just fine when i go there in a webbrowser, what i am doing in my code is replacing those x's with variables from my program and uploading them to the database when they change. Here is my code below: (http stuff is closer to the bottom half) #if defined(ARDUINO) && ARDUINO > 18 #include <SPI.h> #endif #include <Ethernet.h> #include <EthernetDHCP.h>
// MAC Address byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
const char* ip_to_str(const uint8_t*);
// Initialize the Ethernet server library //Server server(8080);
int var1 = 2; int var2 = 4; int var3 = 7; int var4 = 8; int var5 = 1;
byte serverip[] = { 142, 55, 49, 114 }; Client client(serverip, 80); //apache web server running on port 80
void setup() { Serial.begin(9600);
Serial.println("Attempting to obtain a DHCP lease..."); EthernetDHCP.begin(mac);
// Since we're here, it means that we now have a DHCP lease, so we print // out some information. const byte* ipAddr = EthernetDHCP.ipAddress(); const byte* gatewayAddr = EthernetDHCP.gatewayIpAddress(); const byte* dnsAddr = EthernetDHCP.dnsIpAddress(); Serial.println("A DHCP lease has been obtained.");
Serial.print("My IP address is "); Serial.println(ip_to_str(ipAddr)); Serial.print("Gateway IP address is "); Serial.println(ip_to_str(gatewayAddr)); Serial.print("DNS IP address is "); Serial.println(ip_to_str(dnsAddr)); // Start the server Serial.print("Starting Server."); //server.begin(); }
void loop() {
EthernetDHCP.maintain(); // listen for incoming clients // Client client = server.available();
if (client) { Serial.println("Client Pass 1"); // an http request ends with a blank line while (client.connected()) { Serial.println("Client Pass 2"); if (client.available()) { Serial.println("client pass 3 "); char c = client.read(); if (c == '\n') { //Posts values of var1 and var2 to the database using an sql script Serial.println("posting to db"); client.print("GET http://cs14.sheridanc.on.ca/connect.php?var1="); client.print(var1); client.print("&var2="); client.print(var2); client.println("HTTP/1.1 200 OK"); client.println("Content-Type: text/html"); client.println(); client.println("<head>"); client.println("<meta http-equiv=Content-Type content=text/html; charset=utf-8 />"); client.println("<title>Test Status</title>"); client.println("</head>"); client.println("<body>"); client.println("</body>"); break; }
} } // give the web browser time to receive the data delay(1); // close the connection: client.stop(); } }
// Just a utility function to nicely format an IP address. const char* ip_to_str(const uint8_t* ipAddr) { static char buf[16]; sprintf(buf, "%d.%d.%d.%d\0", ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3]); return buf; }
|
|
|
|
|
Logged
|
|
|
|
|
CO, USA
Offline
God Member
Karma: 4
Posts: 706
|
 |
« Reply #1 on: October 05, 2011, 09:42:00 pm » |
I haven't used this, but it appears as if your script is sending out the response it's expecting to get back from the webserver after the get request is processed. the '200 OK' is an http response which would be coming back from the server. Try client.println("HTTP/1.1"); without the 200 OK part. Then don't send the rest of the HTML code you have there. Do you have access to your server logs? I'm going to guess you'll see some illegal request errors. I suspect that the ethernet library has some methods for retrieving the response you get back, so I think it would be instructive to do that, and Serial.print it.
|
|
|
|
|
Logged
|
... it is poor civic hygiene to install technologies that could someday facilitate a police state. -- Bruce Schneier
|
|
|
|
Offline
Jr. Member
Karma: 0
Posts: 54
|
 |
« Reply #2 on: October 05, 2011, 10:56:27 pm » |
I went into the apache error logs and this is what i found [Wed Oct 05 23:53:46 2011] [error] [client 64.228.213.33] client sent HTTP/1.1 request without hostname (see RFC2616 section 14.23): /connect.php does it mean i didnt pick a hostname or that the arduino needs a hostname?
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Tesla Member
Karma: 50
Posts: 6526
Arduino rocks
|
 |
« Reply #3 on: October 05, 2011, 11:19:23 pm » |
The below connects part of the time. //zoomkat 11-13-10 //simple ethernet client test code //for use with IDE 0021 and W5100 ethernet shield //modify the arduino lan ip address as needed //open serial monitor to see what the arduino receives //push the shield reset button to run client again
#include <SPI.h> #include <Ethernet.h> byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; byte ip[] = { 192,168,1,102 }; byte server[] = { 142, 55, 49, 114 }; // Client client(server, 80);
void setup() { Ethernet.begin(mac, ip); Serial.begin(9600); delay(500); Serial.println("connecting..."); if (client.connect()) { Serial.println("connected"); client.print("GET /connect.php?var1=x&var2= HTTP/1.1\r\n"); client.print("Host: cs14.sheridanc.on.ca\r\n"); client.print("Connection: close\r\n"); client.print("\r\n");
} else { Serial.println("connection failed"); } }
void loop() { if (client.available()) { char c = client.read(); Serial.print(c); } if (!client.connected()) { Serial.println(); Serial.println("disconnecting."); client.stop(); for(;;) ; } }
|
|
|
|
|
Logged
|
|
|
|
|
CO, USA
Offline
God Member
Karma: 4
Posts: 706
|
 |
« Reply #4 on: October 05, 2011, 11:24:02 pm » |
I went into the apache error logs and this is what i found [Wed Oct 05 23:53:46 2011] [error] [client 64.228.213.33] client sent HTTP/1.1 request without hostname (see RFC2616 section 14.23): /connect.php does it mean i didnt pick a hostname or that the arduino needs a hostname? I think it means the Apache server you're connecting to is set up to do virtual domain hosting. So without a hostname as part of the request, it doesn't know what virtual host to use to service it. Or, it could be more complicated. See http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html and scroll down a bit, where you'll find the example: For example, a client wishing to retrieve the resource above directly from the origin server would create a TCP connection to port 80 of the host "www.w3.org" and send the lines:
GET /pub/WWW/TheProject.html HTTP/1.1 Host: www.w3.org Note that the GET request specifies a resource (in the form of a path), and the hostname is a seperate transmission immediately following that. I'm not an expert on this, but I think you'll be able to verify this by finding, in your Apache logs, a successful invocation from your web browser. I haven't looked at Apache logs for quite a while. I mostly remember that it's tedious without an analyzer. Looking at http://www.jmarshall.com/easy/http/ I find: HTTP 1.0 defines 16 headers, though none are required. HTTP 1.1 defines 46 headers, and one (Host:) is required in requests. So, I'm not sure how you'd construct the request for HTTP/1.0, but that might be an easier possibility. And as I said, I haven't looked at the library, so I'm wondering why it doesn't do some of this stuff for you, given a complete URL -- maybe the processing involved in parsing is too much overhead for the Arduino, so you have to do all the heavy lifting yourself. ETA: I see you've discovered the Host: header already. I'm afraid I'm out of ideas, at least for now.
|
|
|
|
|
Logged
|
... it is poor civic hygiene to install technologies that could someday facilitate a police state. -- Bruce Schneier
|
|
|
|
0
Offline
Tesla Member
Karma: 50
Posts: 6526
Arduino rocks
|
 |
« Reply #5 on: October 05, 2011, 11:34:12 pm » |
This also works part of the time, but less frequently. //zoomkat 11-13-10 //simple ethernet client test code //for use with IDE 0021 and W5100 ethernet shield //modify the arduino lan ip address as needed //open serial monitor to see what the arduino receives //push the shield reset button to run client again
#include <SPI.h> #include <Ethernet.h>
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; byte ip[] = { 192, 168, 1, 102 }; // Arduino IP address byte server[] = { 142, 55, 49, 114 }; // zoomkat's web site
Client client(server, 80);
void setup() { Ethernet.begin(mac, ip); Serial.begin(9600); Serial.println("starting simple arduino client test"); Serial.println();
delay(1000);
Serial.println("connecting...");
if (client.connect()) { Serial.println("connected"); client.println("GET /connect.php?var1=x&var2=x HTTP/1.0"); client.println(); } else { Serial.println("connection failed"); } }
void loop() { if (client.available()) { char c = client.read(); Serial.print(c); }
if (!client.connected()) { Serial.println(); Serial.println("disconnecting."); Serial.println("=================================="); Serial.println(""); client.stop(); for(;;); } }
|
|
|
|
|
Logged
|
|
|
|
|
Offline
God Member
Karma: 3
Posts: 812
|
 |
« Reply #6 on: October 05, 2011, 11:54:30 pm » |
There are three problems. First, you are not creating a proper HTTP GET request. a GET request, in text, looks something like this: GET /connect.php?var1=x&var2=y HTTP/1.1 Connection: close Host: cs14.sheridanc.on.ca
Each line is terminated by both CR and LF, and the final blank line terminates the request (by terminating the headers of the GET). Second, a delay(1) is probably not enough to make sure the server gets the data, a little bit depending on how far away it is, how lossy the network is, etc. If you need a delay to make sure the server gets the data, try adding a delay(500) instead -- or maybe even delay(5000), if that delay is necessary. A better way would be to wait for the server to send back the "HTTP/1.1 200 OK" response before you close() the connection. Third, and this is more subtle: You should not expect a GET request to be able to always write to a destination. GET requests are generally cacheable in the Internet infrastructure, and some proxy or server cache or whatever on the way may decide that it's already seen a "GET" with the parameters you're posting, and just return the cached response, rather than forwarding the request all the way to your PHP script. You should be using a PUT or a POST. The only difference, compared to a GET, is that you need to add a Content-Length header, which can be 0. Thus, a proper request should probably look like: POST /connect.php HTTP/1.1 Host: your-host-name.com Connection: close Content-length: 14
?var1=x&var2=y
(The body is NOT terminated by CR LF here)
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Jr. Member
Karma: 0
Posts: 54
|
 |
« Reply #7 on: October 06, 2011, 08:26:51 am » |
So this is the new code Serial.println("posting to db");
client.print("POST /connect.php HTTP/1.1"); client.println("Host: cs14.sheridanc.on.ca"); client.println("Connection: close"); client.println("Content-length: 14");
client.println("?var1="); client.print(var1); client.print("&var2="); client.print(var2); Serial.println("posted to db"); Still doesnt work apache shows this in the access logs "POST /connect.php HTTP/1.1Host: cs14.sheridanc.on.ca" 400 368 "-" "-" How do i add CF anf LF?
|
|
|
|
|
Logged
|
|
|
|
|
Seattle, WA USA
Offline
Brattain Member
Karma: 311
Posts: 35470
Seattle, WA USA
|
 |
« Reply #8 on: October 06, 2011, 09:25:19 am » |
How do i add CF anf LF? client.println(); Still doesnt work apache shows this in the access logs "POST /connect.php HTTP/1.1Host: cs14.sheridanc.on.ca" 400 368 "-" "-" The 400 there is a clue. Look up what an HTTP error value of 400 means.
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Jr. Member
Karma: 0
Posts: 54
|
 |
« Reply #9 on: October 06, 2011, 02:23:51 pm » |
Http 400 means a malformed request, so basically the formatting of the information I am sending is not right?
|
|
|
|
|
Logged
|
|
|
|
|
CO, USA
Offline
God Member
Karma: 4
Posts: 706
|
 |
« Reply #10 on: October 06, 2011, 05:16:51 pm » |
Third, and this is more subtle: You should not expect a GET request to be able to always write to a destination. GET requests are generally cacheable in the Internet infrastructure, and some proxy or server cache or whatever on the way may decide that it's already seen a "GET" with the parameters you're posting, and just return the cached response, rather than forwarding the request all the way to your PHP script. You should be using a PUT or a POST.
There are a couple other ways of dealing with this. One would be to use the the cache control header Cache-Control: no-cache The other would be to add another parameter which is set to a random value, thus preventing the request from looking just like the previous ones. Might be that Pragma: no-cache would be better there. Might be simpler for the OP to stay with GET requests until all that is working. ETA: a 3rd variable (ignored by the script) could just be set to the value of millis(), no need to mess with generating a random value.
|
|
|
|
« Last Edit: October 06, 2011, 06:20:13 pm by justjed »
|
Logged
|
... it is poor civic hygiene to install technologies that could someday facilitate a police state. -- Bruce Schneier
|
|
|
|
Hamburg, Germany
Offline
Full Member
Karma: 2
Posts: 190
Hello world!
|
 |
« Reply #11 on: October 06, 2011, 08:51:51 pm » |
When POSTing you need to know and send the content length. I assume the parameters var1 and var2 are not always exactly one character/byte long so the "Content-length: 14" would be correct for "?var1=1&var2=2" (btw, the ? is the seperator for the query string in a URI, needed for GET requests but should not be used when POSTing form data in the http body) but wrong for "?var1=42&var2=23" I agree with justjed, GET is easier to use and adequate for this task. In most default server configurations php automatically adds HTTP headers to prevent caching, so there should not be problems with proxies at all. Adding a random value is also a common practice to prevent caching. Your request should look like: GET /connect.php?var1=1&var2=2&23489 HTTP/1.0 Host: cs14.sheridanc.on.ca Connection: close
And this is how I think it should work: Serial.println("posting to db"); client.print("GET /connect.php?var1="); // Path only, not the complete URI client.print(var1); client.print("&var2="); client.print(var2); client.print("&"); client.print( millis() ); // prevent caching, like justjed said a post before client.println(" HTTP/1.0"); // no need for 1.1 client.println("Host: cs14.sheridanc.on.ca"); client.println("Connection: close"); client.println();
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Jr. Member
Karma: 0
Posts: 54
|
 |
« Reply #12 on: October 06, 2011, 11:17:12 pm » |
When POSTing you need to know and send the content length. I assume the parameters var1 and var2 are not always exactly one character/byte long so the "Content-length: 14" would be correct for "?var1=1&var2=2" (btw, the ? is the seperator for the query string in a URI, needed for GET requests but should not be used when POSTing form data in the http body) but wrong for "?var1=42&var2=23" I agree with justjed, GET is easier to use and adequate for this task. In most default server configurations php automatically adds HTTP headers to prevent caching, so there should not be problems with proxies at all. Adding a random value is also a common practice to prevent caching. Your request should look like: GET /connect.php?var1=1&var2=2&23489 HTTP/1.0 Host: cs14.sheridanc.on.ca Connection: close
And this is how I think it should work: Serial.println("posting to db"); client.print("GET /connect.php?var1="); // Path only, not the complete URI client.print(var1); client.print("&var2="); client.print(var2); client.print("&"); client.print( millis() ); // prevent caching, like justjed said a post before client.println(" HTTP/1.0"); // no need for 1.1 client.println("Host: cs14.sheridanc.on.ca"); client.println("Connection: close"); client.println();
Oh wow this worked, thanks alot! Ive been working at this for so long trying to figure this out lol... This will make future work easier, thanks!
|
|
|
|
|
Logged
|
|
|
|
|
Offline
God Member
Karma: 3
Posts: 812
|
 |
« Reply #13 on: October 09, 2011, 10:52:17 pm » |
client.print("POST /connect.php HTTP/1.1"); // <-- this line has a bug -- no CR/LF client.println("Host: cs14.sheridanc.on.ca"); client.println("Connection: close"); client.println("Content-length: 14");
client.println("?var1="); // <-- this line has a bug -- you want an empty line before this line, not a linebreak in the middle client.print(var1); client.print("&var2="); client.print(var2); Serial.println("posted to db"); Still doesnt work apache shows this in the access logs "POST /connect.php HTTP/1.1Host: cs14.sheridanc.on.ca" 400 368 "-" "-" How do i add CF anf LF? I annotated the code for you. Additionally, the character code for CR is 13, and the string value is "\r". The character code for LF is 10, and the string value is "\n".
|
|
|
|
|
Logged
|
|
|
|
|
Montreal
Offline
Newbie
Karma: 0
Posts: 6
For all your IT Needs - 7-13 IT Solutions
|
 |
« Reply #14 on: February 04, 2012, 10:10:58 am » |
Would anyone know if the connection code will work with GSM Shield or only with an Ethernet Shield?
Thanks Tony
|
|
|
|
|
Logged
|
|
|
|
|
|