Pages: [1]   Go Down
Author Topic: Arduino-Arduino LAN communication - client not connecting to server  (Read 840 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello Arduino guys and gals!

I have come to a dead end trying to make an Arduino client connect to an Arduino server in a LAN.

Let me start with the hardware:
An ADSL router, a 5port switch, a pc and two Mega2560 boards, each with it's Ethernet Shield (W5100). IDE v1.0.1.

I have already set up a server that successfully communicates with the PC - typing "http://192.168.1.192/vi0" at Chrome connects to the board and it replies to the browser as it should.
I have successfully set up a client that receives info from the internet (option 1, see code below) (tweaking some very good bildr code - thanks guys!). If I use the pc's IP as server (option 3), the Arduino client also gets a (LAN) response (nothing special, but it makes a LAN connection all right).

However, when I try to connect the Arduino client to the Arduino server (option 2), nothing happens. server.available() returns nothing, client nothing. It is as if the request never happened.
Yet, the server ethernet connection sometimes halts for a while and it is not accessible from the pc either (Oops! Google Chrome could not connect to 192.168.1.192), at least for a little while and then it works again (some times) without my intervention. At the same time though, the server responds fine to serial input and replies there are no connections open. smiley-confuse

Any ideas? Am I forgetting anything fundamental? Have you witnessed anything similar yourselves??? Is it a bug?

This is the client code
Code:
//ARDUINO 1.0+ ONLY
//ARDUINO 1.0+ ONLY
#include <Ethernet.h>
#include <SPI.h>

////////////////////////////////////////////////////////////////////////
//CONFIGURE
////////////////////////////////////////////////////////////////////////
byte (*server)[4];
byte server1[] = { 174,123,231,247 }; //ip Address of the server you will connect to
byte server2[] = { 192,168,1,192 }; //ip Address of the server you will connect to
byte server3[] = { 192,168,1,14 }; //ip Address of the server you will connect to

//The location to go to on the server
//make sure to keep HTTP/1.0 at the end, this is telling it what type of file it is
String location;
String location1 = "GET /~bildr/examples/ethernet/ HTTP/1.0";
String location2 = "GET /vi0 HTTP/1.0";
String location3 = "GET / HTTP/1.0";

// Do not forget to change MAC address, devices on the same address will not communicate
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
////////////////////////////////////////////////////////////////////////

//EthernetClient client;

char inString[32]; // string for incoming serial data
int stringPos = 0; // string index counter
boolean startRead = false; // is reading?

void setup()
{
  Ethernet.begin(mac);
  Serial.begin(9600);
  Serial.println(Ethernet.localIP());
}

void loop()
{
  if (Serial.available())
  {
    char c = Serial.read();
    delay(100); //wait for serial
    while (Serial.available())
      Serial.read(); //flush serial
    switch (c)
    {
    case '1':
      server = &server1;
      location = location1;
      break;
    case '2':
      server = &server2;
      location = location2;
      break;
    case '3':
      server = &server3;
      location = location3;
      break;
    default:
      return;
    }
    Serial.println("Connecting to: " + String((*server)[0]) + '.' + String((*server)[1]) + '.' + String((*server)[2]) + '.' + String((*server)[3]) + ' ' + location);
    String pageValue = connectAndRead(); //connect to the server and read the output
    Serial.println(pageValue); //print out the findings.
    Serial.println();
  }
}

String connectAndRead()
{
  //connect to the server

  Serial.println("Connecting");
  
  EthernetClient client;

  //port 80 is typical of a www page
  if (client.connect(*server, 80))
  {
    client.println(location);
    client.println();
//    client.println("Host: 192.168.1.192");
//    client.println();
//    client.println("Connection: keep-alive");
//    client.println();
    Serial.println("Connected");
//    client.flush();
  }
  else
  {
    return "Connection failed";
  }

  delay(2000); //wait for response

  if (client.connected())
    Serial.println("Still connected");
  else
  {
    client.stop();
    return "Client unavailable";
  }
    
  if (!client.available())
  {
    client.stop();
    return "No response";
  }
  
  while(client.available())
  {
    char c = client.read();
    Serial.print(c);
  }

  Serial.println("disconnecting.");
  client.stop();
  return "OK";
}

this is the Serial output:

Connecting to: 192.168.1.192 GET /vi0 HTTP/1.0
Connecting
Connected
Still connected
No response

and this is the server code, the part checking for client presence. It returns "false"...

Code:
boolean CDKWebAccess::IsClient()
{
boolean newClient = false;
if (!isEthernet) return false;
if (!client)
{
client = server.available();
newClient = true;
}

if (client)
{
if (newClient)
{
Serial.println("Client detected");
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println();
// client.print("This is");
// PrintLine(" a message");
// PrintLine();
}
return true;
}
else
{
// if (server.available()) return true;
return false;
}
}
« Last Edit: November 14, 2012, 10:29:21 am by dkallergis » Logged

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

Here is my web client code.
http://www.arduino.cc/playground/Code/WebClient

Here is my web server code.
http://www.arduino.cc/playground/Code/WebServerST

They should work together.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I DON'T BELIEVE IT!!! I was stuck for two days and NOW it struck me!

I had the same MAC for client and server! The router did not mind, DHCP worked, requests were coming and going between LAN and internet. BUT when the two devices tried to connect to each other - obviously - the connection failed, badly!

SurferTim, thanks for the super fast reply!

If anyone wants to use the client code, I have made a sketch that depending on serial input connects to a different server / command combination.

Sorry, false alarm!

Edit:
Please be advised that this phenomenon is NOT AS TRIVIAL as it may seem! MOST of our codes are running on the same "random" 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED MAC address, my year-old server, the days old client, bildr code, SurferTim server AND client code, Arduino sample code (IDE v1.0.1) they all have it.

Most samples of server/client code will probably NOT work for direct Arduino-Arduino communication unless you CHANGE THE MAC ADDRESS!
« Last Edit: November 14, 2012, 08:39:19 am by dkallergis » Logged

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

Quote
Most samples of server/client code will probably NOT work for direct Arduino-Arduino communication unless you CHANGE THE MAC ADDRESS!
It's a place holder. You are expected to be smart enough to see that, and use the value that is on the sticker on your shield in it's place.
Logged

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

Quote
Most samples of server/client code will probably NOT work for direct Arduino-Arduino communication unless you CHANGE THE MAC ADDRESS!
Nice catch!!  smiley

I'll change one of the mac addresses in the playground code.
edit: Changed code and added a warning.
« Last Edit: November 14, 2012, 09:51:07 am by SurferTim » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

(@PaulS: I agree about the place holder though I find your comment rude ("You are expected to be smart enough"??). I have also got some considerations regarding the Shield-MAC connection - see below)

(@SurferTim: Edited 1st post too and added a similar comment, thanks)

I guess it will help as a reminder if we keep adding comments to MAC such as "Do not forget to change MAC address, devices on the same address will not communicate"

A similar comment already exists in Arduino code samples (IDE v1.0.1).
// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield

However, IMHO,
1)MAC can not reside permanently in the code, especially if you are using the same code on more than one devices
2)It is not practical to check MAC against the Shield sticker before each compilation
3)MAC should stay with the Arduino and not the Shield, because once you swap Shields you have to reprogram all affected boards!

So, I think I will write a piece of code that stores the address at EEPROM the first time you set it. That is unless there is any kind of serial number inside the Arduino that we can use to generate a MAC that is unique to the board and does not change with every reset.

Any ideas? Any unique information such as a serial number?

If we do this, we will solve this issue permanently!
Logged

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

I think an area of interest might be to identify just what the particular function of the MAC address is relating to the arduino and under what conditions it is important or required. it appears that in some network situations it is critical, and in others it isn't.
Logged

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

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

There's something to be said for changing:

Code:
// this must be unique
byte mac[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

To:

Code:
// The mac must be unique.
// See the MAC sticker on your board, or make something up that doesn't clash with other devices on your network.
// If you have multiple boards, make up a different set of hex numbers for each one.
byte mac[] = {  0x??, 0x??, 0x??, 0x??, 0x??, 0x?? };


That way you are forced to think about it.
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Perhaps we could have more advice about MAC addresses.

From: http://en.wikipedia.org/wiki/MAC_address



Bit b2 in the high-order byte should be a 1, and bit b1 should be a zero. It might be possible to recommend the organization identifier in such a way that randomly-chosen MACs are very unlikely, or impossible, to clash with existing devices on the network, like routers, Macs, PCs, etc.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

(@Nick Gammon: I am with you 100%, for both posts)

(@zoomkat: If anyone has more experience please step in. How I understand it is:

Each device that connects to a network has to have a globally unique MAC address. If only one arduino is present in the network it makes no difference what the MAC address is, as long as this address does not belong to another device, which is super highly unlikely. It is the second device that introduces the problem. This is why all code available works well with the "default" or "place holder" MAC.

However, it is highly recommended that you CHANGE THE MAC ADDRESS to the Shield sticker value or a true random number before this device starts connecting to other arduino boards or the internet. MAC addresses are intended to be a permanent, device specific, globally unique identifier. When you start having thousands or millions of devices with the same "unique" MAC it smells trouble.)

Hope that makes sense. And now it is with great pleasure that I present to you a more permanent solution, using EEPROM to save and retrieve the last three bytes of the MAC address. I read somewhere that the first three bytes are specific to the organisation, so I only change the last three. For those bytes I used http://www.random.org/ to initialise three values from 0 to 255, once and for all for each Arduino board.

OK, it is not the automatic S/N specific address I would have liked, but setting up three numbers each time you buy a new board is not too bad either! Hope it helps!

Code:
/*

  EEPROM MAC address
 
  This sketch saves the three last bytes of MAC to the first
  three positions in EEPROM so that it can later be retrieved
  for Ethernet connectivity. It is very important to have a
  unique MAC addresses for each Arduino board, otherwise the
  boards may fail to connect unexpectedly.
 
  created 14 Nov 2012
  by Dimitris Kallergis

*/

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

//Keep the first definition in comments.
//Use it only to initialise EEPROM MAC on a new Arduino
//Update the last three bytes before use
//Values accepted: decimals 0-255 or 2 hex digits
//Only use unique or random values
//Please do NOT use 0xEF, 0xFE, 0xED!
//byte mac[] = { 0xDE, 0xAD, 0xBE, 255, 255, 255 };

//The last three bytes will be filled in by EEPROM data
byte mac[] = { 0xDE, 0xAD, 0xBE, 0x00, 0x00, 0x00 };

void setup()
{
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial)
  {
    ; // Wait for serial port to connect. Needed for Leonardo only
  }
 
  if (!EEPROMMAC()) // Read/Write/Check EEPROM MAC
  {
    Serial.println("EEPROM MAC failed. Set MAC address.");
    while(true); //do nothing forevermore
  }
 
  Serial.println
  (
    "MAC: "
    + String(mac[0],16) + ':'
    + String(mac[1],16) + ':'
    + String(mac[2],16) + ':'
    + String(mac[3],16) + ':'
    + String(mac[4],16) + ':'
    + String(mac[5],16)
  );
 
  Ethernet.begin(mac);
 
  Serial.println(Ethernet.localIP());

}

void loop()
{
}

boolean EEPROMMAC()
{
  if (!(mac[3] | mac[4] | mac[5])) //MAC to be filled in by EEPROM
  {
    mac[3] = EEPROM.read(0);
    mac[4] = EEPROM.read(1);
    mac[5] = EEPROM.read(2);
    if(!(mac[3] | mac[4] | mac[5])) //all values 0
      return false;
    if((mac[3] & mac[4] & mac[5]) == 0xff) //all values 255 (0xff)
      return false;
  }
  else
  {
    //do not write to EEPROM if nothing changes
    //be careful about how often you write to it
    if (EEPROM.read(0) != mac[3])
      EEPROM.write(0, mac[3]);
    if (EEPROM.read(1) != mac[4])
      EEPROM.write(1, mac[4]);
    if (EEPROM.read(2) != mac[5])
      EEPROM.write(2, mac[5]);
  }
  return true;
}

I call it EEPROMMAC ...and it holds 2^24 - 2 = 16777214 values, or should I say 16777213!
Logged

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

Quote
Each device that connects to a network has to have a globally unique MAC address. If only one arduino is present in the network it makes no difference what the MAC address is, as long as this address does not belong to another device, which is super highly unlikely.

So if I make a direct connection between two arduinos with ethernet shields and use the tcp/ip protocol, communication between the two won't work if both have the same MAC sddress? Where in this direct connection setup would the MAC address of the two arduino ethernet shields checked? I've ordered a mega with an ethernet shield to do some arduino to arduino testing, but just curious about the actual useage of the MAC address.
Logged

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

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

As I understand it, the MAC address is the primary way packets are identified as belonging to a particular device on the network. See here:

http://en.wikipedia.org/wiki/Ethernet_frame

Notice that after the preamble, the destination MAC is first, followed by the source MAC.

All protocols will have that header, and after that (for TCP/IP protocol) is the IP part in which the IP address is stored.

I believe (but may be wrong) that if the destination is on the local network, its MAC address will be in the packet. If not, the MAC address of the router will be in the packet. The router then has the job of finding either the destination MAC (by using the IP address) or another router which may help.

It follows that if two devices on the network have the same MAC (regardless of what IP address they claim to use) they will both respond, at the hardware level (eg. in the Ethernet firmware) to a packet addressed to them.
Logged

Pages: [1]   Go Up
Jump to: