Anybody have ~simple combined server/client code?

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.

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?

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.

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

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.

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

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.

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

        }
      }
    }
  }
}

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

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

while(client.connected() && client.sending()) delay(1);
client.stop();

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.

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

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

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

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

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.

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

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

Server server(84); //server port
Client client(server, 80);
String readString;

The second reference to server will cause an error. It was expecting

byte myserver[] = { 192, 168, 1, 10 }; // the web server for your client code to download
Server server(84); //server port for the server
Client client(myserver, 80); // use the ip address of the web server for the client

Don't use strings for this. Use a character array.
char outBuf[64];

Ok, something that works! I'm using the strings as I'm not that familiar with moving data in/out of arrays. Trying to stay simple for the time being.

#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
byte myserver[] = { 208, 104, 2, 86 }; // zoomkat web page
Server server(84); //server port
Client client(myserver, 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("server/client test 11/25/11"); // 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() //client function to send/receie GET request data.
{
  if (client.connect()) {
    Serial.println("connected");
    client.println("GET /~shb/arduino.txt HTTP/1.0");
    client.println();
  } 
  else {
    Serial.println("connection failed");
    Serial.println();
  }

  while(client.connected() && !client.available()) delay(1); //waits for data
  while (client.connected() || client.available()) { //connected or data available
    char c = client.read();
    Serial.print(c);
  }

  Serial.println();
  Serial.println("disconnecting.");
  Serial.println("==================");
  Serial.println();
  client.stop();

}

There you go! And even waited for the server to close! :slight_smile:
I prefer character arrays because I can use sprintf() to do some easy numeric formatting. If the string works for you, use it.

I think this code is simple enough to where somebody without a lot of code experience could make some interesting arduino monitoring/control setups.

In terms of making it compile, reply #7 is still true.