Ethernet shield not allowing repeated connections

Hello all,

I'm having some trouble getting my new Ethernet Shield to make repeated connections to a php script hosted on my server.

I'm just starting out using the ethernet shield, and found some code at another post that looked like a decent starting point.

(My code will attached in the next post, as the forums won't let me include URLs in my first post)

the result from the serial window:

connecting...
connected
HTTP/1.1 200 OK
Date: Wed, 26 Nov 2008 15:50:47 GMT
Server: Apache/2.2.3 (Debian) PHP/5.2.0-8+etch11
X-Powered-By: PHP/5.2.0-8+etch11
Content-Length: 27
Content-Type: text/html; charset=UTF-8

/nd101 /c1001 1 2 3 4   /et
disconnecting.
connecting...
connected
HTTP/1.1 200 OK
Date: Wed, 26 Nov 2008 15:51:06 GMT
Server: Apache/2.2.3 (Debian) PHP/5.2.0-8+etch11
X-Powered-By: PHP/5.2.0-8+etch11
Content-Length: 27
Content-Type: text/html; charset=UTF-8

/nd101 /c1001 1 2 3 4   /et

At this point, it just hangs -- indefinitely.

It always connects twice, gets the proper result, and then hangs.
Also, there is a delay of approximately 20 seconds between the printing of the first request ending and the printing of "disconnecting".

Also, if I press the reset button on the shield immeadately after the the first request is returned there is no hanging, and I can continue dozens of times with no troubles.

So, where to start looking for the trouble ?

Incidentally, the included web_client example will hang on "connecting.." if I press the reset button to restart the arduino. If I disconnect it from the power instead of pressing the reset button, no problems.

Ultimately, I'm looking to send a request to my script every few seconds and parse the response. So, if there is a better way to start working at this, I'm all ears.

Many thanks for any advice!

My code (as promised):

#include <Ethernet.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192,168,0,51 };
byte server[] = {212,13,194,29};


Client client(server, 80);

enum CLIENT_STATE
{  
      STEP1, STEP2, STEP3, STEP4
};

static CLIENT_STATE client_state;

void setup()
{
  Ethernet.begin(mac, ip);
  Serial.begin(9600);
  
  delay(1000);
}

void loop()
{
  
  if (client_state==STEP1)
  {
    Serial.println("connecting...");
  
  if (client.connect()) {
    Serial.println("connected");
    
    client.println("GET /switchboard/switchtest.php?msg=%2Fnd101+%2Fc1001+%2Frq HTTP/1.1");
    client.println("Host: www.twentyeightninetyone.net");
    client.println("User-Agent: AVR ethernet");
    client.println("Accept: text/html");

    client.println();
  

    client_state=STEP2;
    delay(1000);
  } else {
    Serial.println("connection failed");
    delay(1000);
    client_state=STEP1;
  }
  }
  
  if (client_state==STEP2)
  {
  if (client.available()) {
    char c = client.read();
    Serial.print(c);
    client_state=STEP2;
  }
  else if (!client.connected())
  {    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
    delay(3000);
      client_state=STEP1;
    }

  }
}

Ben,

I just got my Ethernet Shield last week, and found the same problem. It is a bug in the library, where all outgoing connections use the same TCP port number.

Most hosts ignore successive messages from the same port number. To correct this, the port number must change with each successive connection request. This can be corrected by modifying (see lines with PW comment) the client.cpp file located in /hardware/libraries/Ethernet folder, as follows.

extern "C" {
  #include "types.h"
  #include "w5100.h"
  #include "socket.h"
}

#include "Ethernet.h"
#include "Client.h"
#include "Server.h"

Client::Client(uint8_t sock) {
  _sock = sock;
}

Client::Client(uint8_t *ip, uint16_t port) {
  _ip = ip;
  _port = port;
  // 08-11-28 PW: Initialize source port
  _srcport = 0;
}

uint8_t Client::connect() {
  _sock = 255;
  
  for (int i = 0; i < MAX_SOCK_NUM; i++) {
    if (getSn_SR(i) == SOCK_CLOSED) {
      _sock = i;
    }
  }
  
  if (_sock == 255)
    return 0;

  // 08-11-28 PW: Update source port
  _srcport++;
    
  // 08-11-28 PW: Use different source port each connection
  socket(_sock, Sn_MR_TCP, (_srcport + 1024), 0);
  
  if (!::connect(_sock, _ip, _port))
    return 0;
    
  while (status() != SOCK_ESTABLISHED) {
    if (status() == SOCK_CLOSED)
      return 0;
  }
  
  return 1;
}

Also, you will need to change the header file too add the variable to hold the source port number.

#ifndef Client_h
#define Client_h

#include "Print.h"

class Client : public Print {
private:
  uint8_t _sock;
  uint8_t *_ip;
  uint16_t _port;
  // 08-11-28 PW: Added 
  uint16_t _srcport;
public:
  Client(uint8_t);

Cheers,

Paul...

Thanks Paul,

It worked!

Just for completeness: after making the changes you suggested, I also deleted all the .o files in the Ethernet directory to get them to recompile. I don't know if that was necessary, but figured it couldn't hurt.

There are still some strange behavior with the sketch apparently hanging for about 20 seconds after it gets the last byte from the server. I'll see if I can solve that issue myself. If not, I'll start another thread.

Thanks again for your help!

--
Ben

I was getting a similar effect. It would run for many hours sending a message about every minute then hang.

I did wonder why the interface does not have some kind of timeout around it so the application can try to resume?

Anyway, I applied the sugegsted port-changing mod. and we'll see what happens.

Actually I'm not sure the mod was applied. I'm using the Mac version of the IDE and after changing and compiling did not see the timestamp change on the Client.o file (in the same folder as Client.cpp). I'm note sure why. Event renamed it, recompiled the app and got no error. Maybe the IDE keeps it elsewhere?

Did someone post a bug report on the software section?

-j

As I thought, my change had no effect. It seems that the IDE does not recompile any changed library files. (The evidence is that Client.o was not touched.)

What's the easiest way on a Mac with OS/X 10.5.4 to just recompile a single library such as Ethernet?

I guess if this had been reported and fixed there would be a download available - even easier - but I suspect it has not been and I do not know how to initiate this myself.

What's the easiest way on a Mac with OS/X 10.5.4 to just recompile a single library such as Ethernet?

Remove the .o files manually.

-j

Did that. Still no new .o files created in hardware/libraries/Ethernet

Wondered if there's an issue with file permissions although I am the admin user.

The wierd thing is that the app sketch still builds!
Also searched the disk to find if the .o files are hidden elsewhere and found no others.

Any ideas pls?

There is one problem with this fix. If you declare Client as a local variable to a routine and not global, then _srcport ends up being 0 everytime you connect:

void WriteData()
{
Client client;
client.connect();
...
client.disconnect();
}

a new client is created with each call. A fix to this is to make _srcport static.

Client.h

static uint16_t _srcport;

Client.cpp:

uint16_t Client::_srcport = 0;

Also remove from Client::Client()

_srcport = 0;

I've made these changes and it's working well so far. It used to hang after 4 loops, now it's at 30 and still going.

Michael

Still can't make the sketch with the modified Ethernet library. Tried on WinXP - same problem. Looked in hardware\cores\arduinoMakefile and can't see how it's pulling in the library - mind you, I haven't needed to use make for years. Also looked for a Makefile for the library and only found a generic one.

You guys are modifying the library successfully - are you doing that with the standard Arduino IDE or whith what Makefile and on what platform?

The Arduino IDE doesn't use the Makefile (which is there for people who don't want to use the IDE). If you delete the .o files and quit and relaunch the IDE, it should recompile the libraries.

OK Thx. The problem was that I had renamed (not deleted) the .o files so that I could easily reverse the process. Whatever the IDE does in the way of checking for the need to recompile does not allow for this (maybe a loose regexp). Anyway, I moved them elsewhere and they were recompiled. Now let's see whether it works as intended.

BTW. In the event that it hangs for any other reason we'll still have a system in need of a manual reset - no good for unattended operation. If anyone is changing the libraries it would be good to add an error path to avoid this.

Well, the port-changing mod enabled it to run for anywhere up to about 20 hours. After that it got into a state where a call to client.available() always returned false (no matter how long I left it). This happened several times. The work-around I am trying is to detect that situation and in that case issue a call to Ethernet.begin(). We'll see whether this works.

Still running 9 days later. So the verdict is that you need the mod to the library and in your application code detect and treat the condition where it can get into that locked-up state.

@Paul - I just got my ethernet shield in the post and so I'd be interested (and I'm sure the rest of the forum would too) to see what you did in your source to check for the lock-up

OK. This is not the recommended solution as the libraries ought to be fixed. What I did was:

// ready to send something
while (!client.connect()) {
digitalWrite(13,HIGH); // flash LED if it hangs
delay(200);
digitalWrite(13,LOW);
tries++;
if (tries > 100) { // ok we have problem
Ethernet.begin(mac, ip); // solve it by brute force
tries=0;
}
}
// OK to send now
client.print("GET /etc...

As I mentioned above this is not the right fix but a reasonable workaround until the libraries get fixed.

@Paul Tanner

Could you please post all your changes in the libary.
Because mine still hangs up after 20-30 reconnects
to a PHP site.

Thx
Geko

@GekoCH. I only made one change in the library. It's the one (posted above) relating to changing the port number. In the application I made a change that I also posted above. This is the one about restarting the shield if and when it won't connect.

Please post again here if you have these changes and it still hangs. We really need help on this from the author of the library or someone familiar with the code.

ok I've changed those things in the libary and made some changes in my sketch.
Every time I send data to my PHP skript I start the Modul again with:

Ethernet.begin(mac, ip);

like you've done in your sketch.

Thx
Geko