Pages: [1] 2   Go Down
Author Topic: Anybody have ~simple combined server/client code?  (Read 2276 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Tesla Member
***
Karma: 114
Posts: 8899
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Consider the daffodil. And while you're doing that, I'll be over here, looking through your stuff.   smiley-cool

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 168
Posts: 12425
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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?

Logged

Rob Tillaart

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

0
Offline Offline
Tesla Member
***
Karma: 114
Posts: 8899
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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. 
Logged

Consider the daffodil. And while you're doing that, I'll be over here, looking through your stuff.   smiley-cool

Miramar Beach, Florida
Offline Offline
Faraday Member
**
Karma: 115
Posts: 5367
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.  smiley-wink

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?
Logged

0
Offline Offline
Tesla Member
***
Karma: 114
Posts: 8899
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Consider the daffodil. And while you're doing that, I'll be over here, looking through your stuff.   smiley-cool

Miramar Beach, Florida
Offline Offline
Faraday Member
**
Karma: 115
Posts: 5367
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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. smiley
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.
« Last Edit: November 25, 2011, 10:54:47 am by SurferTim » Logged

0
Offline Offline
Tesla Member
***
Karma: 114
Posts: 8899
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
#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="";

        }
      }
    }
  }
}

Logged

Consider the daffodil. And while you're doing that, I'll be over here, looking through your stuff.   smiley-cool

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 547
Posts: 45997
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Miramar Beach, Florida
Offline Offline
Faraday Member
**
Karma: 115
Posts: 5367
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
while(client.connected() && client.sending()) delay(1);
client.stop();
Logged

New River, Arizona
Offline Offline
God Member
*****
Karma: 16
Posts: 906
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Trying to keep my house under control http://www.desert-home.com/

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 547
Posts: 45997
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Miramar Beach, Florida
Offline Offline
Faraday Member
**
Karma: 115
Posts: 5367
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
#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.

« Last Edit: November 25, 2011, 01:09:35 pm by SurferTim » Logged

0
Offline Offline
Tesla Member
***
Karma: 114
Posts: 8899
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.  smiley-sad
Logged

Consider the daffodil. And while you're doing that, I'll be over here, looking through your stuff.   smiley-cool

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 547
Posts: 45997
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

0
Offline Offline
Tesla Member
***
Karma: 114
Posts: 8899
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Code:
#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();
  }
}

Logged

Consider the daffodil. And while you're doing that, I'll be over here, looking through your stuff.   smiley-cool

Pages: [1] 2   Go Up
Jump to: