|
|
View previous topic :: View next topic |
Author |
Message |
ajt
Joined: 07 Sep 2003 Posts: 110
|
HTTP GET using TCP Client |
Posted: Fri Jul 13, 2012 11:05 am |
|
|
Using the CCS stack and demo board, I can run example 13 with TCPserver.exe running on a PC and everything works as it should. (compiler/IDE version 4.134)
I have placed a small PHP script at testani.net (72.34.42.193) that returns the server's UTC time, i.e.
http://testani.net/timestamp.php
which, as you can see, works from a browser. It also works from a small Delphi program I wrote to test it using a HTTP client component.
I am stuck trying to make this work using the CCS stack. I modified example 13 as follows and cannot get a response from the server although it does seem to connect. The essential changes to ex13.c are to change the port to 80 (for HTTP) and the TCPPutArray string to "GET /timestamp.php HTTP/1.1\r\n". I have checked router and server logs and do not see any of the activity from this test but do see it for the browser case.
I've searched the CCS forum as well as have done searches on sending HTTP requests using a TCP client and related topics and cannot figure out what I am going wrong. Any help would be appreciated!
Modified ex13.c follows. You can see I added some LCD output and also some infinite loops to keep any reconnection from happening. I did it this way to not mess with the state machine at all.
Code: | //////////////////////////////////////////////////////////////////////////////
//
// **MODIFIED** ex13.c
//
// A TCP example, where the PIC acts as a TCP client.
//
// NOTE: You MUST change the code in ServerAddrInit() to specify the IP address
// of the PC running TCPSERVER.EXE
//
// NOTE: Change the code in IPAddrInit() to your desired IP address, which
// is based on your network.
//
//////////////////////////////////////////////////////////////////////////////
#define STACK_USE_ICMP 1
#define STACK_USE_ARP 1
#define STACK_USE_TCP 1
#include "ccstcpip.h"
IP_ADDR server;
#define EXAMPLE_TCP_PORT (int16)80
//this function is called by MyTCPTask() when the specified socket is connected
//returns TRUE if BUTTON2 was pressed, therefore we must disconnect the socket
int8 TCPConnectedTask(TCP_SOCKET socket) {
char c;
static int8 counter;
char str[32];
static int8 button1_held;
int16 num_sent;
if (TCPIsGetReady(socket)) {
printf(lcd_putc,"\f");
while (TCPGet(socket, &c)) {
lcd_putc(c);
}
printf(lcd_putc, "\nSOCKET ACTIVE");
}
//when button 1 is pressed: send message over TCP
//when button 2 is pressed: disconnect socket
if (BUTTON1_PRESSED() && !button1_held && TCPIsPutReady(socket)) {
button1_held=TRUE;
// sprintf(str,"BUTTON C=%U",counter++);
strcpy(str,"GET /timestamp.php HTTP/1.1\r\n");
if (TCPIsConnected(socket)){
num_sent = 0;
num_sent = TCPPutArray(socket,str,strlen(str));
TCPFlush(socket);
}
lcd_putc("\f");
printf(lcd_putc, "num_sent: %Lu", num_sent);
lcd_putc("\n");
printf(lcd_putc, str);
}
if (!BUTTON1_PRESSED()) {
button1_held=FALSE;
}
#if defined(BUTTON2_PRESSED())
if (BUTTON2_PRESSED()) {
return(TRUE);
}
#endif
return(FALSE);
}
void MyTCPTask() {
static TICKTYPE lastTick;
static TCP_SOCKET socket=INVALID_SOCKET;
static enum {
MYTCP_STATE_NEW=0, MYTCP_STATE_ARP_REQ=1, MYTCP_STATE_ARP_WAIT=2,
MYTCP_STATE_CONNECT=3, MYTCP_STATE_CONNECT_WAIT=4,
MYTCP_STATE_CONNECTED=5, MYTCP_STATE_DISCONNECT=6,
MYTCP_STATE_FORCE_DISCONNECT=7
} state=0;
static NODE_INFO remote;
TICKTYPE currTick;
int8 dis;
currTick=TickGet();
switch (state) {
case MYTCP_STATE_NEW:
memcpy(&remote.IPAddr, &server, sizeof(IP_ADDR));
printf(lcd_putc,"\fARP REQUEST TO\n");
lcd_display_ip(&server);
state=MYTCP_STATE_ARP_REQ;
case MYTCP_STATE_ARP_REQ:
if (ARPIsTxReady()) {
ARPResolve(&remote.IPAddr);
lastTick=currTick;
state=MYTCP_STATE_ARP_WAIT;
}
break;
case MYTCP_STATE_ARP_WAIT:
if (ARPIsResolved(&remote.IPAddr, &remote.MACAddr)) {
state=MYTCP_STATE_CONNECT;
}
else if (TickGetDiff(currTick, lastTick) > (TICKS_PER_SECOND * 2)) {
state=MYTCP_STATE_ARP_REQ;
}
break;
case MYTCP_STATE_CONNECT:
printf(lcd_putc,"\fCONNECTING TO\n");
lcd_display_ip(&server);
socket=TCPConnect(&remote, EXAMPLE_TCP_PORT);
if (socket!=INVALID_SOCKET) {
lastTick=TickGet();
state=MYTCP_STATE_CONNECT_WAIT;
}
else {
printf(lcd_putc,"\fSOCKET ERROR");
}
break;
case MYTCP_STATE_CONNECT_WAIT:
if (TCPIsConnected(socket)) {
state=MYTCP_STATE_CONNECTED;
printf(lcd_putc,"\fCONNECTED TO\n");
lcd_display_ip(&server);
}
else if (TickGetDiff(currTick, lastTick) > (TICKS_PER_SECOND * 10)) {
state=MYTCP_STATE_FORCE_DISCONNECT;
}
break;
case MYTCP_STATE_CONNECTED:
if (TCPIsConnected(socket)) {
dis=TCPConnectedTask(socket);
if (dis) {
state=MYTCP_STATE_DISCONNECT;
lastTick=currTick;
}
}
else {
printf(lcd_putc,"\fDISCONNECTED");
state=MYTCP_STATE_CONNECT;
printf(lcd_putc, "\fSTOPPED in loop");
while(1); //!!!!!!!!!!!!!!!
}
break;
case MYTCP_STATE_DISCONNECT:
printf(lcd_putc,"\fDISCONNECT FROM\n");
lcd_display_ip(&server);
if (TCPIsPutReady(socket)) {
state=MYTCP_STATE_FORCE_DISCONNECT;
}
else if (TickGetDiff(currTick, lastTick) > (TICKS_PER_SECOND * 10)) {
state=MYTCP_STATE_FORCE_DISCONNECT;
}
break;
case MYTCP_STATE_FORCE_DISCONNECT:
TCPDisconnect(socket);
state=MYTCP_STATE_CONNECT;
printf(lcd_putc, "\fSTOPPED in loop");
while(1); //!!!!!!!!!!!!!!!
break;
}
}
void ServerAddrInit(void) {
//IP address of testani.net
server.v[0]=72;
server.v[1]=34;
server.v[2]=42;
server.v[3]=193;
// server.v[0]=192;
// server.v[1]=168;
// server.v[2]=167;
// server.v[3]=34;
}
void main(void)
{
printf("\r\n\nCCS TCP/IP TUTORIAL, EXAMPLE 13 (TCP CLIENT)\r\n");
Init();
ServerAddrInit();
lcd_init();
printf(lcd_putc,"\fCCS TCP TUTORIAL\nINIT");
StackInit();
while(TRUE) {
StackTask();
MyTCPTask();
}
} | [/code] _________________ Al Testani |
|
|
andrewg
Joined: 17 Aug 2005 Posts: 316 Location: Perth, Western Australia
|
|
Posted: Fri Jul 13, 2012 11:57 am |
|
|
There's two things I can think of:
1. You need a blank line after the request: Code: | strcpy(str,"GET /timestamp.php HTTP/1.1\r\n\r\n"); |
2. HTTP/1.1 requires a Host header (HTTP/1.0 does not): Code: | strcpy(str,"GET /timestamp.php HTTP/1.1\r\nHost: testani.net\r\n\r\n"); |
BTW, all HTTP servers should include the current time in their response headers, so you shouldn't need a special script to return the time, and in that case you could also use a HEAD request instead of a GET. _________________ Andrew |
|
|
dpechman
Joined: 04 Dec 2007 Posts: 43
|
|
Posted: Fri Jul 13, 2012 12:06 pm |
|
|
Hi,
I did it work sometime ago using the same sample and include dns client.
First look seems you forget to include "<CR><LF>" at the end of get sentence HTTP/1.1<CR><LF>
Code: |
IP_ADDR server;
char SERVER_NAME[64]="servername.com";
#define MY_TCP_PORT (int16)80
int8 TCPConnectedTask(TCP_SOCKET socket) {
char c;
static int8 counter;
char str[20];
static int8 button1_held;
if (TCPIsGetReady(socket)) {
while (TCPGet(socket, &c)) {
Lcd_Putc(c);
}
}
if (trigger==1 && TCPIsPutReady(socket)) {
disparar=0;
sprintf(str,"GET /services/srv.php?operation=doLogin HTTP/1.1<CR><LF>");
TCPPutArray(socket,str,strlen(str));
TCPFlush(socket);
}
return(FALSE);
}
void MyTCPTask() {
static TICKTYPE lastTick;
static TCP_SOCKET socket=INVALID_SOCKET;
static enum {
MYTCP_STATE_DNSSET=0, MYTCP_STATE_GET_DNS=1,
MYTCP_STATE_NEW=2, MYTCP_STATE_ARP_REQ=3, MYTCP_STATE_ARP_WAIT=4,
MYTCP_STATE_CONNECT=5, MYTCP_STATE_CONNECT_WAIT=6,
MYTCP_STATE_CONNECTED=7, MYTCP_STATE_DISCONNECT=8,
MYTCP_STATE_FORCE_DISCONNECT=9
} state=0;
static NODE_INFO remote;
TICKTYPE currTick;
int8 dis;
currTick=TickGet();
switch (state) {
case MYTCP_STATE_DNSSET:
DNSResolve(SERVER_NAME);
lastTick = currTick;
state = MYTCP_STATE_GET_DNS;
break;
case MYTCP_STATE_GET_DNS:
if (DNSIsResolved(&server))
{
state = MYTCP_STATE_NEW;
}
else if (TickGetDiff(currTick, lastTick) > (TICKS_PER_SECOND * 30))
{
state = MYTCP_STATE_DNSSET;
}
break;
case MYTCP_STATE_NEW:
memcpy(&remote.IPAddr, &server, sizeof(IP_ADDR));
Lcd_Gotoxy(1,1);
Lcd_Putc("\nARP REQUEST ");
state=MYTCP_STATE_ARP_REQ;
break;
case MYTCP_STATE_ARP_REQ:
if (ARPIsTxReady()) {
ARPResolve(&remote.IPAddr);
lastTick=currTick;
state=MYTCP_STATE_ARP_WAIT;
}
break;
case MYTCP_STATE_ARP_WAIT:
if (ARPIsResolved(&remote.IPAddr, &remote.MACAddr)) {
state=MYTCP_STATE_CONNECT;
//Lcd_Gotoxy(2,1);
//Lcd_Putc("\nCONNECTING ");
Lcd_Gotoxy(2,1);
printf(Lcd_Caracter, "%u.%u.%u.%u", MY_IP_BYTE1, MY_IP_BYTE2, MY_IP_BYTE3, MY_IP_BYTE4);
}
else if (TickGetDiff(currTick, lastTick) > (TICKS_PER_SECOND * 2)) {
state=MYTCP_STATE_ARP_REQ;
}
break;
case MYTCP_STATE_CONNECT:
socket=TCPConnect(&remote, MY_TCP_PORT);
if (socket!=INVALID_SOCKET) {
lastTick=TickGet();
state=MYTCP_STATE_CONNECT_WAIT;
}
else {
//Lcd_Gotoxy(2,1);
//Lcd_Putc("\nSOCKET ERROR ");
}
break;
case MYTCP_STATE_CONNECT_WAIT:
if (TCPIsConnected(socket)) {
state=MYTCP_STATE_CONNECTED;
leds=16;
Lcd_Gotoxy(2,1);
Lcd_Putc("\nCONNECTED! ");
}
else if (TickGetDiff(currTick, lastTick) > (TICKS_PER_SECOND * 10)) {
state=MYTCP_STATE_FORCE_DISCONNECT;
}
break;
case MYTCP_STATE_CONNECTED:
if (TCPIsConnected(socket)) {
dis=TCPConnectedTask(socket);
if (dis) {
state=MYTCP_STATE_DISCONNECT;
lastTick=currTick;
}
}
else {
Lcd_Gotoxy(2,1);
Lcd_Putc("\nDISCONNECTED ");
state=MYTCP_STATE_CONNECT;
}
break;
case MYTCP_STATE_DISCONNECT:
Lcd_Gotoxy(2,1);
Lcd_Putc("\nDISCONNECTING ");
if (TCPIsPutReady(socket)) {
state=MYTCP_STATE_FORCE_DISCONNECT;
}
else if (TickGetDiff(currTick, lastTick) > (TICKS_PER_SECOND * 10)) {
state=MYTCP_STATE_FORCE_DISCONNECT;
}
break;
case MYTCP_STATE_FORCE_DISCONNECT:
TCPDisconnect(socket);
state=MYTCP_STATE_CONNECT;
break;
}
}
|
|
|
|
ajt
Joined: 07 Sep 2003 Posts: 110
|
|
Posted: Fri Jul 13, 2012 4:24 pm |
|
|
andrewg wrote: |
2. HTTP/1.1 requires a Host header (HTTP/1.0 does not): Code: | strcpy(str,"GET /timestamp.php HTTP/1.1\r\nHost: testani.net\r\n\r\n"); |
BTW, all HTTP servers should include the current time in their response headers, so you shouldn't need a special script to return the time, and in that case you could also use a HEAD request instead of a GET. |
Thanks! This was it and I now have it working. The reason I am using the PHP script is the returned UTC string is in the exact format I need it in. I could have done all of the conversion in PIC code but this was much easier. I still have to parse the header for the date and I just have to go further to get at the PHP return. I am using the required number of TCPGet calls until I get to the string of interest. _________________ Al Testani |
|
|
ajt
Joined: 07 Sep 2003 Posts: 110
|
|
Posted: Fri Jul 13, 2012 4:26 pm |
|
|
dpechman wrote: | Hi,
I did it work sometime ago using the same sample and include dns client.
First look seems you forget to include "<CR><LF>" at the end of get sentence HTTP/1.1<CR><LF>
|
This is very useful code to me as I need to add the DNS section as well. Thanks! _________________ Al Testani |
|
|
dpechman
Joined: 04 Dec 2007 Posts: 43
|
|
Posted: Fri Jul 13, 2012 5:00 pm |
|
|
yeah, this is a pretty good way to keep pic connected to internet. I am also using this approach in my last designs.
In the php side you can do a long polling to keep connection always up with minimum bandwidth.
If you want, we can exchange some ideas about it.
Now my system is using http client, dns client, get and set passing data from pic to php webservices and the other way around. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|