I have an uno with an ethernet shield. I understand that you should be able to set up 4 simultaneous tcp connections. I want one so that the uno can send data out when it wants (uno as client) and I want one so that the uno can be sent information when required (uno as server). I have been looking around for a while now and can't find any examples of this use case though a few people have mentioned that this is something they would like to be able to do.
metamind:
I want one so that the uno can send data out when it wants (uno as client) and I want one so that the uno can be sent information when required (uno as server).
That's not quite the definition of client and server. The naming depends on which side initiates the connection request. It's the Client that sends a connection request and a Server that accepts a connection request. Once the connection has been established then either end can send at any time.
To accept connections, use an EthernetServer object. To initiate connections, use an EthernetClient object.
//zoomkat 7-03-12, combined client and server
//simple button GET with iframe code
//for use with IDE 1.0
//open serial monitor and send an g to test client and
//see what the arduino client/server receives
//web page buttons make pin 5 high/low
//use the ' in html instead of " to prevent having to escape the "
//address will look like http://192.168.1.102:84 when submited
//for use with W5100 based ethernet shields
//note that the below bug fix may be required
// http://code.google.com/p/arduino/issues/detail?id=605
#include <SPI.h>
#include <Ethernet.h>
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //assign arduino mac address
byte ip[] = { 192, 168, 1, 102 }; // ip in lan assigned to arduino
byte gateway[] = { 192, 168, 1, 1 }; // internet access via router
byte subnet[] = { 255, 255, 255, 0 }; //subnet mask
EthernetServer server(84); //server port arduino server will use
EthernetClient client;
char serverName[] = "web.comporium.net"; // (DNS) zoomkat's test web page server
//byte serverName[] = { 208, 104, 2, 86 }; // (IP) zoomkat web page server IP address
String readString; //used by server to capture GET request
//////////////////////
void setup(){
pinMode(5, OUTPUT); //pin 5 selected to control
Ethernet.begin(mac,ip,gateway,gateway,subnet);
server.begin();
Serial.begin(9600);
Serial.println("server/client 1.0 test 7/03/12"); // keep track of what is loaded
Serial.println("Send an g in serial monitor to test client"); // what to do to test client
}
void loop(){
// check for serial input
if (Serial.available() > 0)
{
byte inChar;
inChar = Serial.read();
if(inChar == 'g')
{
sendGET(); // call client sendGET function
}
}
EthernetClient 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 on browser request
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 1.0 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 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(5, HIGH); // set pin 5 high
Serial.println("Led On");
}
if(readString.indexOf("off") >0)//checks for off
{
digitalWrite(5, LOW); // set pin 5 low
Serial.println("Led Off");
}
//clearing string for next read
readString="";
}
}
}
}
}
//////////////////////////
void sendGET() //client function to send and receive GET data from external server.
{
if (client.connect(serverName, 80)) {
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();
}
I am having trouble connecting as a client though. I have tried a whole bunch of things (most of the afternoon) but no success.
My Uno can get onto the network fine and I can ping it. The trouble always comes when the Uno tries to connect. This:
if (client.connect(server, port)) {
almost always fails. I have tried it with a TCP server on port 7000 that I set up that I could telnet to from my network. I have tried it using port 80 and connecting to googe (as in the WebClient example). I have tried a whole bunch but no joy. Is there a way to dig in and find out why it is failing.
The connection also seems inconsistant. My TCP server usually registers the connection and sometimes a message gets through from the Uno even on a connection that has failed.
while (status() != SnSR::ESTABLISHED) {
delay(1);
if (status() == SnSR::CLOSED) {
_sock = MAX_SOCK_NUM;
return 0;
}
}
I have tried lengthening the delay but, again, no joy. I have also tried with the latest versions of the code from github. My TCP server is never registering the CLOSED event.
The problem is that the server.begin() is taking and reserving all available sockets (4) for the server instance, leaving none for any client starting an outgoing connection. If you must have both available at the same time, you have to change the Ethernet library code. Let the server just use 3 of the 4 sockets so you still have one for the client. You have to take care when changing the code because MAX_SOCK_NUM is used to signal an error, so just redefining it might cause more problems than you expect.
I have got it working for my requirements now. I think the main problem was that the connection was intolerant of delays in transmission. It was very flaky when I tried it using it with a remote server (in Germany, I'm in the UK). It seems to be fine on the LAN. I suspect there are some "delay(xxx)"s that would need to be increased somewhere to make it work with internet latencies.