Go Down

Topic: Anybody have ~simple combined server/client code? (Read 2791 times) previous topic - next topic

zoomkat

Looking for some simple combined client server code to possibly preclude reinventing the wheel on this subject. The desired setup would to have the server code running awating an incomming request to act on, with the client availabe to make a request to another server when some event is detected by an arduino input.
Google forum search: Use Google Advanced Search and use Http://forum.arduino.cc/index in the "site or domain:" box.

robtillaart

Sounds a bit like two threads which can't be done, implying a server polling if there is a connection... and between the polls the client could do her requests...

Do you have any figures about what you want for responsiveness, how often the server will be connected, how often the client will make requests?

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

zoomkat

My thoughts are that the server code runs in a typical main loop. The client code would be in a conditional if at the start of the main loop, such that if the condition is met, the client code would run. Upon completion of the client code, the main loop with the server code would once again continue to loop. No need to consider competing request or critical timing at this time. 
Google forum search: Use Google Advanced Search and use Http://forum.arduino.cc/index in the "site or domain:" box.

SurferTim

I don't see why you couldn't do that, but I haven't tried it yet. The "server client" would need to be a different variable than the "client client".

Now you will understand why it is the server that closes the connection that is the signal you are finished sending.  ;)

If I understand your intent, you will receive a request from a remote client as a "server client", then respond to that "server client" by opening another page as a "client client", downloading it and uploading that page to the "server client". Correct?

zoomkat

Quote
If I understand your intent, you will receive a request from a remote client as a "server client", then respond to that "server client" by opening another page as a "client client", downloading it and uploading that page to the "server client". Correct?


My current idea is to have the arduino monitoring an input (serial port, analog or digital point) in the same server loop. If a condition is met (something received on the serial port, digital point change, or an analog value reached), the internal client loop would be activated, sending a notification via a get request or an email. Somebody/thing on the receiving end of the notification would return a response to the server loop via a get request. The server loop would receive the get request and take action based on the data contained in the request (make a digital pin high/low or reposition a servo. These activities already exist as ~simple stand alone code, the question is if they can be successfully combined.
Google forum search: Use Google Advanced Search and use Http://forum.arduino.cc/index in the "site or domain:" box.

SurferTim

#5
Nov 25, 2011, 04:45 pm Last Edit: Nov 25, 2011, 04:54 pm by SurferTim Reason: 1
You have the code in the thread link below. Combine the server code in the loop. Leave the client code like it is. Instead of using an 'e' to send email or request a page, use whatever trigger you wish. :)
http://arduino.cc/forum/index.php/topic,79949.0.html

Edit: Change one of the "client" variables. Like for the server, use something like "sClient". That is up to you.

zoomkat

Below is a simple copy/paste attempt at combining the client and server functions. As usual it has errors, and not knowing anything about C programming beyond copy/paste, I haven't figured it out yet. May have a simple fix, or may have fundimental flaws not easily corrected.

Code: [Select]

#include <SPI.h>
#include <Ethernet.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = { 192, 168, 1, 102 }; // ip in lan
byte gateway[] = { 192, 168, 1, 1 }; // internet access via router
byte subnet[] = { 255, 255, 255, 0 }; //subnet mask
Server server(84); //server port
Client client(server, 80);
String readString;

//////////////////////

void setup(){

  pinMode(4, OUTPUT); //pin selected to control
  //start Ethernet
  Ethernet.begin(mac, ip, gateway, subnet);
  server.begin();

  //enable serial data print
  Serial.begin(9600);
  Serial.println("servertest1"); // so I can keep track of what is loaded
}

void loop(){
  // Create a client connection
  Client client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();

        //read char by char HTTP request
        if (readString.length() < 100) {

          //store characters to string
          readString += c;
          //Serial.print(c);
        }

        //if HTTP request has ended
        if (c == '\n') {

          ///////////////
          Serial.println(readString); //print to serial monitor for debuging

          //now output HTML data header
             if(readString.indexOf('?') >=0) { //don't send new page
               client.println("HTTP/1.1 204 Zoomkat");
               client.println();
               client.println(); 
             }
             else {
          client.println("HTTP/1.1 200 OK"); //send new page
          client.println("Content-Type: text/html");
          client.println();

          client.println("<HTML>");
          client.println("<HEAD>");
          client.println("<TITLE>Arduino GET test page</TITLE>");
          client.println("</HEAD>");
          client.println("<BODY>");

          client.println("<H1>Zoomkat's simple Arduino button</H1>");
         
          client.println("<a href=\"/?on\" target=\"inlineframe\">ON</a>");
          client.println("<a href=\"/?off\" target=\"inlineframe\">OFF</a>");

          //client.println("<IFRAME name=inlineframe src=\"res://D:/WINDOWS/dnserror.htm\" width=1 height=1\">");
          client.println("<IFRAME name=inlineframe style=\"display:none\" >");         
          client.println("</IFRAME>");

          client.println("</BODY>");
          client.println("</HTML>");
             }

          delay(1);
          //stopping client
          client.stop();

          ///////////////////// control arduino pin
          if(readString.indexOf("on") >0)//checks for on
          {
            digitalWrite(4, HIGH);    // set pin 4 high
            Serial.println("Led On");
          }
          if(readString.indexOf("off") >0)//checks for off
          {
            digitalWrite(4, LOW);    // set pin 4 low
            Serial.println("Led Off");
          }
          //clearing string for next read
          readString="";

        }
      }
    }
  }
}

Google forum search: Use Google Advanced Search and use Http://forum.arduino.cc/index in the "site or domain:" box.

PaulS

The first argument to the Client class is supposed to be an IP address to connect to, not the instance of the Server.

SurferTim


The first argument to the Client class is supposed to be an IP address to connect to, not the instance of the Server.

...along with a few other errors.

I tried the setup I thought would work. I used a combination of my email code and server code, and they do work together. I can send email as a client and serve web pages as a server.

I would post the code, but the code has some custom function calls that I have added to my ethernet library, and I don't know how the code would work without those functions.
I have "client.sending()" and "client.remoteIP()" functions. The "client.sending()" function is my concern. It returns the number of bytes remaining in the transmit buffer. I wait until the transmit buffer is empty before sending another packet or closing the connection.
Code: [Select]
while(client.connected() && client.sending()) delay(1);
client.stop();


draythomp

I do this in several devices.  You can grab any of the code off my site that you want.  Basically, it isn't hard at all, just have the server code you already have and then do a client call.  The problem with using my code is that it isn't simple because I tweaked it to handle the board locking up, remote server not responding, multiple tries, etc.  If you look it over you'll get the gist of it and should be ok.

I did this initially because I wanted the correct time from the NIST hosts and also to respond locally to html requests.  It just kind of grew from there.  I also have a couple of special calls in the ethernet library to return things I need, but you'll see them; just ignore them.
Trying to keep my house under control http://www.desert-home.com/

PaulS

Quote
...along with a few other errors.

Logic errors, maybe. I didn't read it all. Changing the Client constructor call allowed the code to at least compile.

SurferTim

#11
Nov 25, 2011, 06:46 pm Last Edit: Nov 25, 2011, 07:09 pm by SurferTim Reason: 1
Hi Paul. It did have some other problems. Compiling ok with this does not mean success.
I tried this and it work as a web server and email client.
Look through the code for remarks. There are changes you must make.
Compile and upload. Open the serial monitor. Wait for ready.
Press 'e' and enter, and the email goes as before.
Use a web browser to access the web server and you get "BLAH BLAH HAR HAR".
Code: [Select]
#include <SPI.h>
#include <Ethernet.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

// Enter your network stuff here
byte ip[] = { 192, 168, 1, 2 };
byte gateway[] = { 192, 168, 1, 1 };
byte subnet[] = { 255,255,255,0 };

// Enter ip of email server
byte eserver[] = { 1, 1, 1, 1 };

Server server(80);

void setup()
{
 Serial.begin(9600);
 pinMode(4,OUTPUT);
 digitalWrite(4,HIGH);
 Ethernet.begin(mac, ip, gateway,subnet);
 server.begin();
 delay(2000);
 Serial.println("Ready");
}

byte ipBuf[4];
char outBuf[256];

void loop()
{
 // this does the email send part
 // enter 'e' and it sends
 byte inChar;

 inChar = Serial.read();

 if(inChar == 'e')
 {
     if(sendEmail()) Serial.println("Email sent");
     else Serial.println("Email failed");
 }

 // This is the server part.
 // listen for incoming clients
 Client client = server.available();
 if (client) {
   boolean currentLineIsBlank = true;
   Serial.print("Client connected ");
   
   while (client.connected()) {
     if (client.available()) {
       char c = client.read();
       if (c == '\n' && currentLineIsBlank) {
         sprintf(outBuf,"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<html><head></head><body bgcolor=#8080FF><H1>BLAH BLAH HAR HAR</H1>");
         client.write(outBuf);
         
     for(int i=0; i<50;i++)
     {
       if(!client.connected()) break;
     
         for (int x = 0; x < 6; x++) {
           sprintf(outBuf,"This is outer loop %d and inner loop %d blah blah blah har har har blah blah blah<br>\r\n",i,x);
           client.write(outBuf);
         }
     }

         break;
       }
       if (c == '\n') {
         currentLineIsBlank = true;
       }
       else if (c != '\r') {
         currentLineIsBlank = false;
       }
     }
   }

   client.write("<H1>Done!</H1></body></html>\r\n\r\n");

   client.stop(); // this is the signal you are finished sending!
   
   Serial.println("done");
 }
}

byte sendEmail()
{
 byte thisByte = 0;
 byte respCode;

 Client client(eserver,25);
 
 if (client.connect()) {
   Serial.println("connected");
 } else {
   Serial.println("connection failed");
   return 0;
 }

 if(!eRcv(client)) return 0;

// replace ip with your ethernet shield ip address  
 client.write("helo 192.168.1.2\r\n");

 if(!eRcv(client)) return 0;
 
// Enter the sender email address here
 client.write("MAIL From: <me@mydomain.com>\r\n");
 
 if(!eRcv(client)) return 0;

// Enter recipient here
 client.write("RCPT To: <you@yourdomain.com>\r\n");

 if(!eRcv(client)) return 0;

 client.write("DATA\r\n");

 if(!eRcv(client)) return 0;

// Enter recipient here  
 client.write("To: You <you@yourdomain.com>\r\n");

// Enter sender here
 client.write("From: Me <me@mydomain.com>\r\n");
 
 client.write("Subject: Arduino email test\r\n");
 
 client.write("This is from my Arduino!\r\n");
 
 client.write(".\r\n");

 if(!eRcv(client)) return 0;

 client.write("QUIT\r\n");

 // wait for server to close the connection!
 while(client.connected())
 {
   if(client.available()) Serial.write(client.read());
 }

 client.stop();
 
 Serial.println("disconnected");
 
 return 1;
}

byte eRcv(Client client)
{
 byte respCode;
 byte thisByte;
 
 while(!client.available()) delay(1);

 respCode = client.peek();

 while(client.available())
 {  
   thisByte = client.read();    
   Serial.print(thisByte);
 }

 if(respCode >= '4')
 {
   efail(client);
   return 0;  
 }
 
 return 1;
}

void efail(Client client)
{
 byte thisByte = 0;

 client.write("QUIT\r\n");

 while(!client.available()) delay(1);

 // wait for the server to close the connection!
 while(client.connected())
 {
   while(client.available())
   {  
     thisByte = client.read();    
     Serial.print(thisByte);
   }
 }
 
 client.stop();
 
 Serial.println("disconnected");
 
}

Let me know if you have problems. I had to do a little editing for change points and remove those function calls you do not have.


zoomkat

This is fustrating. the code I posted was not the combined server/client code I had put together. I did a cold boot on the laptop yesterday and the added client changes were apparently not appropriately saved. I'll see if I can do the cut paste attempt again.  :(
Google forum search: Use Google Advanced Search and use Http://forum.arduino.cc/index in the "site or domain:" box.

PaulS

Quote
Compiling ok with this does not mean success.

I agree completely. My only point was that, from a compilation point of view, there was just one error. I hadn't looked beyond that, nor had I tried to actually run the code.

zoomkat

Below is what I was trying, with the first error at the Client line.

Code: [Select]

#include <SPI.h>
#include <Ethernet.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = { 192, 168, 1, 102 }; // ip in lan
byte gateway[] = { 192, 168, 1, 1 }; // internet access via router
byte subnet[] = { 255, 255, 255, 0 }; //subnet mask
Server server(84); //server port
Client client(server, 80);
String readString;

//////////////////////

void setup(){

  pinMode(4, OUTPUT); //pin selected to control
  Ethernet.begin(mac, ip, gateway, subnet);
  server.begin();
  Serial.begin(9600);
  Serial.println("servertest1"); // so I can keep track of what is loaded
}

void loop(){
  // check for serial input
  if (Serial.available() > 0)
  {
    byte inChar;
    inChar = Serial.read();
    if(inChar == 'e')
    {
      sendGET(); // call sendGET function
    }
  } 

  Client client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();

        //read char by char HTTP request
        if (readString.length() < 100) {

          //store characters to string
          readString += c;
          //Serial.print(c);
        }

        //if HTTP request has ended
        if (c == '\n') {

          ///////////////
          Serial.println(readString); //print to serial monitor for debuging

            //now output HTML data header
          if(readString.indexOf('?') >=0) { //don't send new page
            client.println("HTTP/1.1 204 Zoomkat");
            client.println();
            client.println(); 
          }
          else {
            client.println("HTTP/1.1 200 OK"); //send new page
            client.println("Content-Type: text/html");
            client.println();

            client.println("<HTML>");
            client.println("<HEAD>");
            client.println("<TITLE>Arduino GET test page</TITLE>");
            client.println("</HEAD>");
            client.println("<BODY>");

            client.println("<H1>Zoomkat's simple Arduino button</H1>");

            client.println("<a href=\"/?on\" target=\"inlineframe\">ON</a>");
            client.println("<a href=\"/?off\" target=\"inlineframe\">OFF</a>");

            //client.println("<IFRAME name=inlineframe src=\"res://D:/WINDOWS/dnserror.htm\" width=1 height=1\">");
            client.println("<IFRAME name=inlineframe style=\"display:none\" >");         
            client.println("</IFRAME>");

            client.println("</BODY>");
            client.println("</HTML>");
          }

          delay(1);
          //stopping client
          client.stop();

          ///////////////////// control arduino pin
          if(readString.indexOf("on") >0)//checks for on
          {
            digitalWrite(4, HIGH);    // set pin 4 high
            Serial.println("Led On");
          }
          if(readString.indexOf("off") >0)//checks for off
          {
            digitalWrite(4, LOW);    // set pin 4 low
            Serial.println("Led Off");
          }
          //clearing string for next read
          readString="";

        }
      }
    }
  }
}

//////////////////////////
void sendGET()
{
  if (client.connect()) {
    Serial.println("connected");
    client.println("GET /~shb/arduino.txt HTTP/1.0");
    client.println();
  }
  else {
    Serial.println("connection failed");
    Serial.println();
    //return;
  }

  while (client.available()) {
    char c = client.read();
    Serial.print(c);
  }

  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
    Serial.println("==================");
    Serial.println();
    client.stop();
  }
}

Google forum search: Use Google Advanced Search and use Http://forum.arduino.cc/index in the "site or domain:" box.

Go Up