Arduino Ethernet and multiple socket server connections

Greetings! If you are finding this writeup useful, please leave a comment. I originally shared these modifications in April 8, 2013. In February 2015, I went through them again using the current Arduino 1.6.0. They still work, but I did tweak the source code notes a bit to be clearer. – Allen

  • 2014/04/03: I just started using GitHub and found all the Arduino sources there, including this bug report which seems to discuss and address this issue. I will be reviewing it when I have time to see if those fixes take care of this bug.
  • 2014/04/08: This is, by far, the most viewed article on this site. I suppose I should do more posts about Arduino Ethernet.
  • 2013/04/09: I have done some more tweaks to the code listed in this article, and will try to update them when I have a chance. I will probably spin it off in to a whole new article on an easy “drop in” telnet server I am working on.
  • 2014/04/14: Fixed some HTML escape codes in the source code. (Thanks, Matt!)
  • 2014/04/16: You can now get an Ethernet shield shipped from the US for $11.49.
  • 2014/04/19: In the comments, Petr Stehlík pointed out that it doesn’t look like a check against incoming IP address is done, meaning that if any packet was received with the same port, it would just be accepted. I will need to investigate the rest of the code and see if it does that check. If not, you could blast a packet to an Arduino and as long as you match the port, it would accept it. That seems real bad, but should be very easy to fix, if needed.
  • 2015/02/15: I just checked these updates against the Arduino 1.6.0 release, and they still work. I am updating the notes on this page to note where the libraries folder is found on Mac OS X, and to clarify where one of the changes goes. I have zipped up my changed and places them here: EthernetMultiServer.zip This may allow a clean 1.6.0 install to “Import Library” and work, but I have not tested that yet. Also, Arduino forum user SurferTim has contributed another way to accomplish this without fixing the library. He has posted a Telnet example in the Playground that talks directly to the Wiznet 5100 chip to keep the incoming connections straight. Very clever (and similar to what I had to do in the library to track the remote ports and keep them separated). Cool
  • 2015/05/22: Similar to the SurferTim approach, a comment by Gene provides another standalone way to do this in code without having to modify the library. He includes a full example in his comment.

NOTE: The links and prices given below may be out of date. Since then. I discovered this seller (kbellenterprises) on e-Bay. They offer some low-cost Arduino clone items. They have always been responsive, and ship very fast. They currently have an UNO clone for $8.49, and a Wiznet 5100 Ethernet shield for $11.49.

The Arduino Ethernet shield (or the $17.99 workalike made by SainSmart) adds internet support to the Arduino. The limited memory of the Arduino does not have to run a full TCP/IP stack. Instead, the Ethernet shield uses a Wizpro chip that handles Ethernet, TCP, UDP and IP protocols. This particular chip, Wizpro W5100, supports four simultaneous connections. This means you could have an Arduino sketch that opens four different websites at the same time, or you could run a server that allows up to four simultaneous users to connect.

At least, you could if the Ethernet library worked right. The way it was designed (I call it a bug or at least an oversight), the existing library would only allow four incoming connections if each one was listening on a different port. For example, if you have port 23 set up to monitor incoming TELNET connections, and one user was connected, any other attempts to connect would be refused until the first connection was closed. I wanted to use the “up to four connections” part to still allow other users to connect, and then tell them “The system is busy. Go away.”

My first attempt to do this was to just create two server instances:

EthernetServer server1(23);
EthernetServer server2(23);

I then modified the WebServer example and trimmed everything out except what I wanted. My main addition was this second server instance, and a check for connections to it while processing the primary connection. It looks like this (see notes afterwards):

// MultiServer Demo

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

byte      mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 0, 100);

EthernetServer server1(23);
EthernetServer server2(23);

void setup()
{
Serial.begin(9600);
while (!Serial);

// start the Ethernet connection and the server:
Ethernet.begin(mac, ip);
server1.begin();
server2.begin();
Serial.print("\nServer is listening at ");
Serial.println(Ethernet.localIP());
}

void loop()
{
EthernetClient client2;

// listen for incoming clients
EthernetClient client1 = server1.available();
if (client1) {
Serial.println("Client A connected.");
client1.println("Greetings, program!");

while(client1.available()>0) client1.read(); // Gobble

// Loop while client is connected.
while (client1.connected())
{
client2 = server2.available();
if (client2.connected()) {
Serial.println("Client B connected. Getting rid of them...");
client2.println("\nThe system is busy. Try back later.\n");
delay(1);
client2.stop();
Serial.println("Client B disconnected.");
}
// Then handle the actual client.

// If data is available, just read it and write it back to the user.
if (client1.available())
{
char c = client1.read();
if (c>0) Serial.write(c);
}
} // end of while... go back and do it again.

// If here, we must no longer be connected.
delay(1);
// close the connection:
client1.stop();
Serial.println("Client A disconnected.");
}
}

My plans was to wait for a connection. Once I had one, I would sit in a loop (as long as they remained connected) and check a second server instance to see if an additional connection attempt was made. If a second attempt was made, I’d send them a quick status message, then shut them down and go back to monitoring the main connection.

This should work, but doesn’t. It produced unexpected results:

Server Output:

Serving at 10.0.0.42
Server is listening at 10.0.0.42
Client 1 connected.
Client 2 connected. Getting rid of them…
Client 2 disconnected.
Client 1 disconnected.

Client (telent) Output:

alsmb:~ allenh$ telnet 10.0.0.42
Trying 10.0.0.42…
Connected to 10.0.0.42.
Escape character is ‘^]’.
Greetings, program!
The system is busy. Try back later.
Connection closed by foreign host.
alsmb:~ allenh$

It seemed the Ethernet could not distinguish between the two connections. I altered the server config to use different ports:

EthernetServer server1(23);
EthernetServer server2(2323);

Perhaps I could let 23 (telnet) be the main port, and 2323 be the status port. This provided much better results.

Server Output:

Server is listening at 10.0.0.42
Client 1 connected.
hello (I typed this from telnet)
(then, I made a second connection from another terminal, to port 2323)
Client 2 connected. Getting rid of them…
Client 2 disconnected.

On the first terminal, I was able to type “hello” and continue my connection, while the second terminal connected, then received the “Go away” message (after pressing some keys to generate some data to wake up the Ethernet code).

So it could work, but not with the same port.

Thanks to a forum post I found earlier explaining how to obtain the remote connection’s IP address, I was aware that the source code to the Ethernet libraries was part of the Arduino IDE, and that it was easy to make changes.

I decided to take a look and see if I could figure out how this Wiznet chip works.

Wiznet W5100

The Wiznet chip is an independent device. The Arduino sends it commands via the SPI bus (like sending byte commands to it) and then data can be read and written back, similarly to talking to a serial port. The Wiznet chip can be programmed to listen to up to four different socket connections, and then it takes care of the rest. The Ardunio basically says “Hey, Wiznet… Listen for connections on Port 23 of Socket 0” and then the Arduino code will query the Wiznet chip saying “Is anyone there?” and if so, handle accordingly.

Inside the Ethernet library code, I saw that it had an array to hold the ports the user was configuring. When you do EthernetServer begin(23), it puts a 23 in the first available slot then programs the Wiznet chip accordingly. These slots are how the Arduino knows which socket of the Wiznet to query. And that is where the problem is.

If you do “EthernetServer server1(23)” followed by “server1.being()”, slot 0 is set up with 23 and Wiznet socket 0 is programmed to listen for port 23 connections. If you then do “EthernetServer server2(23)” followed by “server2.begin()”, then slot 1 is set up with 23 and Wiznet socket 1 is programed to listen to port 23 connections. The Wiznet hardware is fine even with all four of it’s sockets listening to the same port. It tracks the actual connection internally.

But the Arduino code ONLY tracks the port number. So, if someone connects to the first socket 0 port, and is using it, then someone tries to connect to port 23 again, the Wiznet will hook them up to socket 1. The Arduino code makes a mistake, and when it checks for data, it grabs the first slot that matches the desired port. So, it keeps reading and writing data to slot 0 (socket 0) and never sees the second port 23 connection.

To resolve this, I made a few minor changes to the Arduino ethernet library code. First, I added secondary storage to track four remote ports (the ports used on the connecting client), and then added a bit of code that walked through all the available sockets trying to match up local server port number AND remote client port…

And it worked the first time, much to my amazement!

Here are my notes and modifications. There are a few things I did which I am not certain are correct, but they worked so I am sharing them. I will make a note of the parts I am unclear on.

Ethernet Library Modifications:

/*--------------------------------------------------------------------------*/
// 2015-02-15: Verified against Arduino 1.6.0.
//
// To fix the Ethernet library so it correctly allows multiple connections
// to the same port, the following files will need to be modified:
//
// libraries/Ethernet/src/Ethernet.h
// libraries/Ethernet/src/Ethernet.cpp
//
// libraries/Ethernet/src/EthernetClient.cpp
// libraries/Ethernet/src/EthernetClient.h
//
// libraries/Ethernet/src/EthernetServer.cpp
//
// On Mac OS X, these are embedded inside the Arduino.app package. Browse
// to that in the Finder, then right-click and select "Show Package
// Contents" and then you can go to:
//
// Contents/Resources/Java/libraries
//
// Is there a better way?
/*

Modify the following files:

1) Ethernet.h: The Ethernet object currently only tracks which Port the
socket is listening to. Add the following array to hold the remote Port.

Add this after static "uint16_t _server_port[MAX_SOCK_NUM];"

// ACH - added
static uint16_t _client_port[MAX_SOCK_NUM]; // ACH

2) Ethernet.cpp: Add the declaraction of the new array.

Add this after "uint16_t EthernetClass::_server_port[MAX_SOCK_NUM]"

// ACH - added
uint16_t EthernetClass::_client_port[MAX_SOCK_NUM] = { 0, 0, 0, 0 }; // ACH

3) EthernetClient.h: Add prototypes for the new functions, and declare a
new local variable that will track the destination port of this client.

Add this in the private: section

// ACH - added
uint16_t _dstport; // ACH

// ACH - added
uint8_t *getRemoteIP(uint8_t remoteIP[]); // ACH
uint16_t getRemotePort(); // ACH

4)  EthernetClient.cpp: When the Client object is stopped, it resets the
_server_port to zero. We should probably do this for the new _client_port.
In void EthernetClient::stop():

Add after this: EthernetClass::_server_port[_sock] = 0;

// ACH - added
EthernetClass::_client_port[_sock] = 0; // ACH

Add these two functions at the bottom of the file:

// ACH - added
uint8_t *EthernetClient::getRemoteIP(uint8_t remoteIP[]) // ACH
{
W5100.readSnDIPR(_sock, remoteIP);
return remoteIP;
}

uint16_t EthernetClient::getRemotePort() // ACH
{
return W5100.readSnDPORT(_sock);
}

5) EthernetServer.cpp: This code has to be modified so when it checks for
a connection, it checks both the Port (existing code) AND the remote
client's port (new code). If the connection has never been made, it will
initialize the remote port varaible correctly.

Add the following code to available()

EthernetClient EthernetServer::available()
{
accept();

for (int sock = 0; sock < MAX_SOCK_NUM; sock++) {
EthernetClient client(sock);
if (EthernetClass::_server_port[sock] == _port &&
(client.status() == SnSR::ESTABLISHED ||
client.status() == SnSR::CLOSE_WAIT)) {

// ACH - added
// See if we have identified this one before
if (EthernetClass::_client_port[sock] == 0 ) {
client._dstport = client.getRemotePort();
EthernetClass::_client_port[sock] = client._dstport;
return client;
}
if (EthernetClass::_client_port[sock] != client._dstport) {
// Not us!
continue;
}
// ACH - end of additions
//if (client.available()) { // ACH - comment out
// XXX: don't always pick the lowest numbered socket.
return client;
//} // ACH - comment out
}
}

return EthernetClient(MAX_SOCK_NUM);
}

...and code to write():

size_t EthernetServer::write(const uint8_t *buffer, size_t size)
{
size_t n = 0;

accept();

for (int sock = 0; sock < MAX_SOCK_NUM; sock++) {
EthernetClient client(sock);

if (EthernetClass::_server_port[sock] == _port &&
// ACH - added
EthernetClass::_client_port[sock] == client._srcport && // ACH
client.status() == SnSR::ESTABLISHED) {
n += client.write(buffer, size);
}
}

return n;
}

*/
/*--------------------------------------------------------------------------*/

During this research, I also found this part to be bothersome:

if (client.available()) {
// XXX: don't always pick the lowest numbered socket.
return client;
}

Unlike the EthernetClient.available(), the one for EthernetServer really shouldn’t be checking for data. It’s checking to see if a brand new connection has been made, then the code will be checking for data available elsewhere. For this to not just always return client would mean you would get a connection, but never see it until there is data. You couldn’t use this code to write a server that someone telnets to and it just spits out something (like a status or a time). It looks like it would force the remote user to send data first before the Arduino code even knows the connection is there.

I commented out the if so it always returns client, since it will bypass that if it finds no matching socket. It seems to work.

Bug?

Coming soon… Multi user BBS for Arduino!

59 thoughts on “Arduino Ethernet and multiple socket server connections

  1. Bruce durant

    Has anybody tried this with a combination of webserver and NTP/UTP code. My code and comments pleas for help are on the arduino forum at http://arduino.cc/forum/index.php?topic=159138.new;topicseen#new

    I’ve been tearing my hair out for 6 months trying to get that combination to work. I’ve only just concluded that the debris left in the RX buffer following an external POST/GET request is screwing over the NTP code. and that implies that the NTP code is hijacking the socket! Purging the buffer completely gets the NTP code returning values again but taking the last rnrn out of the buffer then screws up the TCP code!!

    If the code above stops sockets from being hijacked then maybe not only can several connections to the Arduino coexist but a mix of web and UDP as well.

    Reply
    1. allenhuffman Post author

      I will take a look. The Arduino Ethernet hardware can maintain four independent socket connections at a time, but the Ethernet library was not coded to allow this from the server side. I will be glad to help you figure it out.

      Reply
  2. Pingback: Sub-Etha Software’s Arduino Telnet server | Sub-Etha Software

  3. RP

    Could you post an example sketch that shows how you are using multiple connections for the same port?

    Reply
    1. Allen Huffman Post author

      Yes, I can do that. One example right now is my Sub-Etha Telnet Server. It has a main loop that shows how I use those modifications. Look for the blocks of code with “#if defined(TELNET_MULTISERVER)” before them. Those are the specific things that enable listening on the same port while a connection is in progress. But be warned… It’s a rather large piece of code. Maybe just those sections would give you an idea. http://subethasoftware.com/2013/04/15/sub-etha-softwares-arduino-telnet-server/

      Reply
  4. Eduardo de Mier

    Hi Allen.
    Thanks for publishing your work.
    I have worked out an Arduino example that
    – get’s an ip per DHCP
    – reads an UDP broadcast sent from a host on a fixed port.
    – replies to the host’s ip and sends its own ip as an info so the host may connect to the Arduino webserver through a browser

    I am now at the point to add a second socket to run a webserver in parallel which is what the host is supposed to connect to.
    Do you think this will work with the standard ethernet library?

    Best regards.
    Eduardo

    Reply
    1. Allen Huffman Post author

      I do not think that will work on the stock ethernet. The stock ethernet treats any incoming connection as the same, and sends data back to whatever connected first, even if it’s a second connection on a different port.

      Reply
      1. Gene

        I maybe wrong, but I believe your confused as to how the Ethernet lib works.

        You are not supposed to create server1 AND server2. You only need to create server1 (unless your wanting to listen to a dif port at the same time).

        In your looping code you do a client = server1.available();
        next you save the reference to client in your codes list of active clients (as well as what ever proc your code needs to do with each client) and continue with your loop, Server1 is still listening for connections so if another client has connected, the next time through your loop when you do client = server1.available(), you’ll get the second connected client, which again, your code needs to save in its list of active clients. clients should be removed from that list as they disconnect. the wiznet code does not track what happens to the client, only if the socket is still in use or not. the array of socket you refereed to, is actually a very small pool of sockets that is pulls from anytime it needs a new socket for listening (or initiating an outbound connection).

        The W5100 has a 4 socket limit so, you can only have 4 simultaneous connections. but nothing in the code will fix that.

        The W5200 has 8 socket limit and is almost identical to the W5100, it use a slightly modified version of the W5100 lib.

        P.S. the web server code “Webduino” has great example of what I described above. I used it for a small home automation web server running on a mega2560 with a w5100 to begin with and later a w5200.

        hope that helps.
        Gene

        Reply
        1. Allen Huffman Post author

          You are correct about how the library is *supposed* to work. Unless they have fixed the bug, though, I was never able to get it to work as it should.

          If you know of an example that lets multiple telnets work at the same time, I’d like to see how they did it.

          Reply
          1. Gene

            Here is the code.

            /* exampleMultiTelnetServer.ino */
            /* 
             *  Created: May 21, 2015
             *
             *  Created by Gene Reeves to demonstrate how the W5100 eithenet handles multiple connections
             *  using a single server object instance.
             * 
             *  once the sketch is loaded on your arduino and you see the start up banner display in the
             *  Serial Monitor, fire up your favorite telnet client and connect a few instances.
             *  
             *  from the serial monitor you can send text to one or all clients. Use '*" for the ID to send
             *  to all, otherwise use the ID you wish to send to, using this format to send,
             *   "ID:TEDXT_TO_SEND".  That should make everything as clear as mud  :-)
             *
             *  Dependencies:
             *
             *	uses LinkedList class from here https://github.com/ivanseidel/LinkedList
             *	to store list of connected clients.
             *
             *  uses StringStream class from here https://gist.github.com/cmaglie/5883185
             *  Not sure why this was not a part of the StringObject to start with..
             *
             *	uses elapsedMillis class from here http://playground.arduino.cc/Code/ElapsedMillis
             *  much improved version (for Teensy brand mcu's) here https://www.pjrc.com/teensy/td_timing_elaspedMillis.html
             *  Unless I am mistaken, I beleive this code was originated by Paul Stoffregen of www.pjrc.com
             *  If you are not famialar with Paul or his Teensy microcontroller, you would do yourself a 
             *  solid to spend some time reviewing his code and you can't beat the Teensy 3.1 for 
             *  price/performance/support!!!   
             *  Teensy 3.1 - 32bit-ARM  mcu @ 72MHz (overclockable to 168MHz) w/ 256K flash / 64K ram / USB
             *  for under $20.  https://www.pjrc.com/teensy/index.html
             *
             *  BTW, I am in no way affilaited with Paul or PJRC, I just think he built an awesome mcu.
             *
             */
            
            
            #include <SPI.h>
            #include <LinkedList.h>
            #include <elapsedMillis.h>
            #include <StringStream.h>
            #include <Arduino.h>
            #include <EthernetUdp.h>
            #include <EthernetServer.h>
            #include <EthernetClient.h>
            #include <Ethernet.h>
            #include <Dns.h>
            #include <Dhcp.h>
            #include <IPAddress.h>
            #include <Server.h>
            #include <Client.h>
            
            
            /*  DEFINES  */
            										 
            /*****************************************************/
            /*  Change the following to suite your environment.  */
            #define TELNET_SERVER_PORT 23
            #define TELNET_SERVER_MAC 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
            #define TELNET_SERVER_IP 192, 168, 1, 177
            #define TELNET_SERVER_GATEWAY 192, 168, 1, 1
            #define TELNET_SERVER_NETMASK 255, 255, 255, 0
            #define SERIAL_BAUD 115200
            #define WELCOME_BANNER_STRING "Welcome to MultiTelnetServer.\r\nType 'exit' to disconnect\r\n"
            #define GOODBYE_BANNER_STRING "Come Back Again,   Goodbye.."
            
            #define APP_BANNER_STRING "\r\n\r\n\tMultiTelnetServer Example\r\n  This example application strives to\r\ndemonstrate using the Wiznet W5x00\r\nEthernet Shield's Arduino library usage\r\nwhen serving mulitple concurrent\r\nconnects using a single 'server object'\r\ninstance."
            #define SERVER_LISTENING_STRING "\tServer Listening on"
            
            /******************************************************/
            
            
            /*
             *	This is required to add RemoteIP, RemotePort support to the EthernetClient class
             *  I stole it from here http://forum.arduino.cc/index.php?topic=210857.0
             */
            //namespace ethernet_fix
            //{
            	#include <utility/w5100.h>
            
            	template<typename Tag, typename Tag::type M>
            	struct AccessMember{
            		friend typename Tag::type get(Tag){ return M; }
            	};
            
            	struct EthernetClient_Socket{
            		typedef uint8_t EthernetClient::*type;
            		friend type get(EthernetClient_Socket);
            	};
            
            	template struct AccessMember < EthernetClient_Socket, &EthernetClient::_sock > ;
            
            	IPAddress RemoteIP(EthernetClient &c){
            		byte remoteIP[4];
            		W5100.readSnDIPR(c.*get(EthernetClient_Socket()), remoteIP);
            		return (remoteIP);
            	}
            
            	uint16_t RemotePort(EthernetClient &c){
            		return W5100.readSnDPORT(c.*get(EthernetClient_Socket()));
            	}
            //} // namespace "ethernet_fix"
            /*
             *  EthernetClientEx - Because there is still no RemoteIP or RemotePort
             *  properties built in to th current EthernetClient!!
             *
             */
            
            class EthernetClientEx :
            	public EthernetClient
            {
            protected:
            	uint8_t _sock; // hack to get access to socket #
            public:
            	EthernetClientEx(const EthernetClient &orig) : EthernetClient(orig) {}
            	IPAddress remoteIP() { return RemoteIP((EthernetClient &)(*this)); }
            	int16_t remotePort() { return RemotePort((EthernetClient &)(*this)); }
            
            	bool isSameSock(const EthernetClientEx &c) { return (_sock == c._sock); }
            };
            
            
            /*
             *	ClientItem is class to wrap EthernetClient for storage on linked list
             *  we will use it to add a ts (millis at connection time) and an index.
             *
             */
            class ClientItem
            {
            public:
            	unsigned long timestamp;
            	int index;
            	size_t recv_cnt;
            	String recv_buffer;
            	EthernetClientEx *client;
            
            	ClientItem() { timestamp = millis(); index = -1; client = (EthernetClientEx *)false; }
            	virtual ~ClientItem() {	delete client; /* release memory */}
            	
            	unsigned long elapsed(void) { unsigned long ts = millis(); return (ts - timestamp); }
            };
            
            /*
             *  ClientList is linkedlist for storing connected clients. 
             *  For now, we'll just use it to store our clients, but should
             *  expand this close to include testing all clients for disconnects,
             *  testing all clients for pending recv data and sending data
             *  to all connected clients.
             */
            
            class LinkedClientList :
            	public LinkedList<ClientItem*> //ClientList;
            {
            public:
            	//EthernetServer *server;
            
            	ClientItem *getClientItem(int idx)
            	{
            		for (ListNode<ClientItem *> *n = root;n;n=n->next)
            		{ 
            			if (n->data->index == idx)
            				return n->data;
            		}
            		return (ClientItem *)0;
            	}
            	
            	bool exists(const EthernetClientEx &ece)
            	{
            		for (ListNode<ClientItem *> *n = root; n; n = n->next)
            			if (n->data->client->isSameSock(ece))
            				return true;
            		return false;
            	}
            
            	void drop(int idx)
            	{
            		ClientItem *cli;
            		int real_idx = -1;
            		int ci = 0;
            		for (ListNode<ClientItem *> *n = root; n; n = n->next)
            			if (n->data->index != idx)
            				ci++;
            			else
            			{
            				cli = n->data;
            				real_idx = ci;
            				break;
            			}
            
            		if (real_idx != -1)
            		{
            			if (cli->client->connected())
            				cli->client->stop();
            			cli->index = -1;
            			remove(real_idx);
            		}
            	}
            
            	size_t send(const String &s, int idx)
            	{
            		size_t ret = 0;
            		ClientItem * cli = getClientItem(idx);
            		if (cli)
            		{
            			ret = cli->client->print(s);
            			cli->client->flush();
            		}
            		return ret;
            	}
            
            	size_t send2All(const String &s)
            	{
            		size_t ret = 0;
            		for (ListNode<ClientItem *> *n = root; n; n = n->next)
            		{
            			ret += n->data->client->print(s);
            			n->data->client->flush();
            		}
            		return ret;
            	}
            };
            
            LinkedClientList ClientList;
            
            // Enter a MAC address and IP address for your controller below.
            // The IP address will be dependent on your local network.
            // gateway and subnet are optional:
            byte mac[] = { TELNET_SERVER_MAC };
            IPAddress ip(TELNET_SERVER_IP);
            IPAddress gateway(TELNET_SERVER_GATEWAY);
            IPAddress subnet(TELNET_SERVER_NETMASK);
            
            // buffer to hold input from console
            StringStream con_buffer("");
            
            // telnet defaults to port 23
            EthernetServer server(TELNET_SERVER_PORT);
            
            /* forward's */
            void server_check_new_connections(void);
            void server_check_client_recv(void);
            int server_accept(EthernetClientEx *enetcli);
            bool clientExists(const EthernetClientEx &c);
            bool test_for_cmd(const String &itm, const String &src);
            size_t console_recv(void);
            void proc_line(StringStream &ss);
            
            size_t client_recv(ClientItem *cli);
            void client_disconnecting(ClientItem *cli);
            void client_disconnected(ClientItem *cli);
            
            size_t send_to(int idx, const String &str);
            size_t send_to_all(const String &str);
            
            /*********************************************************/
            void setup()
            {
            
              /* add setup code here */
            	// reserve some space for input buffer
            	con_buffer.reserve(256);
            
            	// Open serial communications and wait for port to open:
            	Serial.begin(SERIAL_BAUD);
            	delay(3000);  // 3 second delay for Serial to connect.
            
            	pinMode(10, OUTPUT);
            	digitalWrite(10, HIGH);
            	pinMode(4, OUTPUT);
            	digitalWrite(4, HIGH);
            
            	// initialize the ethernet device
            	Ethernet.begin(mac, ip, gateway, subnet);
            	// start listening for clients
            	server.begin();
            
            	// Print "App Banner" and "Server Listening" notice.
            	Serial.println(F(APP_BANNER_STRING));
            	Serial.println(F(SERVER_LISTENING_STRING));
            	Serial.print(F("\t\t"));
            	Serial.print(ip);
            	Serial.print(':');
            	Serial.println(TELNET_SERVER_PORT);
            	Serial.println(F("\r\n\r\n"));
            
            }
            
            void loop()
            {
            
              /* add main program code here */
            
            	// check for any new clients
            	server_check_new_connections();
            
            	// give up a timeslice
            	yield();
            
            	// check to see if any of the clients 
            	// have recv data pending
            	if (ClientList.size() > 0)
            		server_check_client_recv();
            
            	// give up a timeslice
            	yield();
            
            	// check to see if console has any 
            	// pending recv data.
            	if (Serial.available())
            		console_recv();
            
            	// give up a timeslice
            	yield();
            }
            
            /*********************************************************/
            
            size_t console_recv(void)
            {
            	size_t ret = 0;
            	int c = 0;
            	while ((c = Serial.read()) >= 0)
            	{
            		if (c == 10)
            		{
            			proc_line(con_buffer);
            			con_buffer = String("");
            			con_buffer.begin();
            			continue;
            		}
            		if (c != 13)
            		{
            			con_buffer += (char)c;
            			ret++;
            		}
            	}
            	return ret;
            }
            
            void proc_line(StringStream &ss)
            {
            
            	//	Console input should be in the for of
            	//	"ID:string_literal"
            	//	where: 
            	//		ID is client index to send to or "*" (all)
            	//		string_literal is string to send
            	//
            	// check to ensure 2nd char is a ":"
            	if ((ss.length() < 3) || (ss.charAt(1) != ':'))
            	{
            		Serial.print(F("Invalid Console Input \""));
            		Serial.print(ss);
            		Serial.print(F("\"\r\nPlease use the following format:\r\n\t"));
            		Serial.println(F("\"ID:string_literal\"\r\n"));
            		Serial.flush();
            		return;
            	}
            	int idx = -1;
            	Serial.print(F(" first char is '"));
            	Serial.print(ss.charAt(0));
            	Serial.print(F("',  "));
            	if (ss.charAt(0) != '*')
            	{
            		idx = ss.parseInt();
            	}
            	Serial.print(F("idx="));
            	Serial.print(idx);
            	Serial.print(F(", indexOf(':')="));
            	Serial.println(ss.indexOf(':'));
            	ss = ss.substring(1 + ss.indexOf(':'));
            	ss += F("\r\n");
            	if (idx < 0)
            		ClientList.send2All(ss);
            		//send_to_all(ss);
            	else
            		ClientList.send(ss, idx);
            }
            
            size_t console_print_connected_count(void)
            {
            	size_t ret =
            		Serial.print(F("\t\t")) +
            		Serial.print(ClientList.size()) +
            		Serial.println(F(" connected client(s).\r\n"));
            	Serial.flush();
            	return ret;
            }
            
            bool test_for_cmd(const String &itm, const String &src)
            {
            	String tst(src);
            	tst.toLowerCase();
            	return tst.startsWith(itm);
            }
            
            void server_check_new_connections(void)
            {
            	EthernetClient obj = server.available();	
            	if (obj)
            	{
            		// convert to EthernetClientEx
            		EthernetClientEx new_client(obj);
            		// is it a new connection?
            		if (!ClientList.exists(new_client))
            		{
            			// accept new connection
            			server_accept((EthernetClientEx *)&new_client);
            
            			// send welcome	banner
            			new_client.println(F(WELCOME_BANNER_STRING));
            			new_client.flush();
            		}
            	}
            }
            
            int server_accept(EthernetClientEx *enetcli)
            {
            	// add itm to list
            	ClientItem *itm = new ClientItem();
            	itm->timestamp = millis();
            	itm->index = ClientList.size();
            	itm->client = new EthernetClientEx((*enetcli));
            	ClientList.add(itm);
            
            	// print notice on console
            	Serial.print(F("Accepted new connection ("));
            	Serial.print(itm->index);
            	Serial.print(F(") from "));
            	Serial.print(enetcli->remoteIP());
            	Serial.print(':');
            	Serial.println(enetcli->remotePort());
            	Serial.println();
            	Serial.flush();
            
            	// print connected count
            	console_print_connected_count();
            
            	// return items index
            	return itm->index;
            }
            
            void server_check_client_recv(void)
            {
            	if (ClientList.size() == 0) return;
            	ClientItem *itm;
            	for (int idx = ClientList.size() - 1; idx >= 0; idx--)
            	{
            		itm = ClientList.get(idx);
            		if (itm->client->connected()==0)
            		{
            			client_disconnected(itm);
            			continue;
            		}
            		if (itm->client->available())
            		{
            			size_t rc = client_recv(itm);
            			if (rc > 0)
            			{
            				// echo to Serial port
            				Serial.print(F("Client #"));
            				Serial.print(itm->index);
            				Serial.print(F(" sent \""));
            				Serial.print(itm->recv_buffer);
            				Serial.println('\"');
            				Serial.flush();
            			}
            			// rc will == 0 if nothing received
            			// rc will == -1 if client entered "exit"
            		}
            		yield();
            	}
            }
            
            size_t client_recv(ClientItem *cli)
            {
            	int c;
            	EthernetClientEx *cIn = (EthernetClientEx *)cli->client;
            	cli->recv_buffer = "\0";
            	cli->recv_cnt = 0;
            	while ((c = cIn->read()) >= 0)
            	{
            		cli->recv_buffer += (char)c;
            		cli->recv_cnt++;
            	}
            	// check to see if they typed "exit"
            	if (test_for_cmd(String(F("exit")), cli->recv_buffer))
            	{
            		client_disconnecting(cli);
            		delay(1); // give up timeslice
            		cli->client->stop();
            		Serial.print(F("called client->stop() for #")); Serial.println(cli->index); Serial.flush();
            		return -1;
            	}
            	return cli->recv_cnt;
            }
            
            void client_disconnecting(ClientItem *cli)
            {
            	Serial.print(F("Client #"));
            	Serial.print(cli->index);
            	Serial.println(F(" is disconnecting."));
            	// send Goodbye Banner
            	send_to(cli->index, String(F(GOODBYE_BANNER_STRING)));
            	Serial.flush();
            	delay(1);
            	cli->client->stop();
            }
            
            void client_disconnected(ClientItem *cli)
            {
            	// print notice on console
            	Serial.print(F("Client #"));
            	Serial.print(cli->index);
            	Serial.print(F(" was connected for "));
            	Serial.print(cli->elapsed() / 1000);
            	Serial.print(F(" seconds, and has disconnected."));
            	Serial.flush();
            
            	// remove from list of clients
            	ClientList.drop(cli->index);
            	(*cli) = (*(ClientItem *)(unsigned long)0);
            	// print connected count
            	console_print_connected_count();
            
            	// this causes seg fault ??
            	//delete cli;
            }
            
            size_t send_to(int idx, const String &str)
            {
            	return ClientList.send(str, idx);
            }
            
            size_t send_to_all(const String &str)
            {
            	return ClientList.send2All(str);
            }
            

            Ok, if that code don’t make it as clear as mud, then I don’t know what is wrong with the world, LOL..j/k.. Really, I hope this helps someone..

            Gene

          2. Allen Huffman Post author

            That looks impressive – I will check it out when I get some Arduino time.

            It does look like we are on the same page — I noticed you had to access some device functions directly from that code, like getting the remote IP. At the time I started hacking the Ethernet library to fix it, I did not realize those could even be done from the main sketch. (I am used to operating systems where you have the concept of system state versus user state so I am just not used to being able to access anything from a “user” program.) Now I understand what you were getting at. The library can’t do it, but you can add code to a sketch to add the missing capabilities.

            For folks that do not want to edit the Arduino library (and have to fix it every time a new update comes out), pushing all of this in to the sketch would be a nice solution. What we need is this approach isolated so it could just be added to a Sketch in another tab and called from setup()/loop() with some C calls to make it easy for novice programmers to deal with.

            Nice job! I will update my article to reference your response/example, too.

  5. andy pollitt

    Dear Allen

    I am fairly new to Arduinos in general. I have 6 sensors with ethernet outputs, I can communicate with the sensors from the arduino very simply using the Telnet example on the arduino website. However, what I would like to do is by using an ethernet switch, talk to each sensor individually. I want to connect to them all during the initialisation of the arduino programme as I need to communicate sequentially in around 1 millisecond. I would like to select each sensor by its IP address and then communicate with it and wait for a response.

    I am yet to find an example code that shows something like this. Could you give me some pointers please.

    Thanks
    Andy

    Reply
    1. Allen Huffman Post author

      Andy – your Arduino will have one IP address. The ethernet hardware, if it’s the chipset like I have, can support up to four socket connections at the same time. So, four “telnet” connections open at the same time, but that is the hardware limit. There are challenges/problems with this, due to limitations (bugs) in the Arduino networking software.

      Could you describe how you wish it to work? You could have a listener/server and when it sees “1” it displays the status of that input. With my fixes to the ethernet library, you could even have it listening to multiple connections at the same time and responding. I already have most of this code written for something like this.

      Give me an idea of how you see it being used, and I can offer some suggestions.

      Reply
    2. Allen Huffman Post author

      Andy — I re-read your message. The switches are IP based? So you have six switches, each with their own address, and you want the Arduino to telnet to each switch and get the status? If so, you won’t be able to do this, since the ethernet chip (if it is the one I am using) only have four sockets. You could connect to four of the switches at a time, and that would be all.

      Reply
  6. andy pollitt

    Hi Allen,

    I can live with using just 3 sensors each with independent IP Addresses (through an ethernet switch). I just want to do something quite simple really:

    Setup the connections to the sensors (switches), then keep these 3 connections concurrently running. The using a for loop, sequentially send a command over the ethernet to an individual sensor (so I must be able to specify which sensor to communicate with at each instant), then await the response from the sensor. I will just continue in the loop. The time scale that I would like to go through all of the detectors by is around 30 milliseconds. A little bit longer wouldn’t kill me but probably less than 100 ms.

    Could you point me to a simple example of something like this?

    Thanks,
    Andy

    Reply
  7. andy pollitt

    I want to keep all connections running because it takes too long to start and stop the connections for the purpose of what I require.

    Reply
    1. Allen Huffman Post author

      I understand. Does something talk to the Arduino? Or is all this code running on the Arduino? I had some ethernet relay boards years ago, so I think I understand the type of situation.

      I will try to find some time to do some tests on outgoing connections. They may also require updates to the Networking Arduino library to properly work.

      — A

      Reply
  8. andy pollitt

    The arduino sends a command to a sensor, this then returns a binary value. This part works for a single sensor I can read information in and I see it over the serial port. I send commands over the serial and get data back.

    I also use the PWM pins (I am using a Due). I have found a library which enables me to change the PWM frequency from the default to 30 Hz (I am using it to control the opening time of a valve). Basically, I use the infomation read in from the ethernet to change the PWM duty cycle. Atleast that’s the theory and for a single channel that would work but I need to have atleast 3 on the same arduino because my algorithm controls 3 valves using the data from 3 sensors.

    I have read that the ethernet can maintain 4 connections at once (on the arduino website) but I have not seen an example of reading and writing to more than one (with the ability to select by IP which one to read and write to).

    Thanks,
    Andy

    Reply
  9. Vinny

    tried to apply these modifications and add things got a bunch of errors from EthernetServer.cpp

    If i want to run a web server, a really really simple html page with sensor data, meanwhile logging it to the SD card while keeping track of time through NTP…
    Is it even possible?

    Im pretty much a noob when it comes to writing code and C++\Processing, but since i got into it i pretty much learned it through examples and other people’s code. I understand the basics now and keep learning new stuff as i go.
    What did i manage to get working by now:
    – I have been able to set up a web server that displays a simple html page with sensor data.
    – I have been able to send and recieve NTP time correctly and without problems, BUT the web server part refused to work in conjunction with the NTP. As a result, i couldnt connect to the server through LAN or my phone.

    So individually they work, but when put together (NTP + WebServer) the NTP wins… weird…

    Reply
    1. Allen Huffman Post author

      That may be the same problem… When a response packet comes back for the NTP time protocol, the networking code may be handing it off to the web server socket or vise versa. I really need to find time to hook my unit back up and experiment with this. If this is the problem, my fixes should make it work. I have not tried mixing TCP and UDP though.

      Reply
  10. Scott

    I am prototyping some environment sensors using etherten arduino and dht22 humidity and temp sensor. The sensors can communicate using mqtt to rabbitmq via Xbee as well as being polled Zabbix 2.2.0 using the zabbix.agent item feature.

    I have found an intermittent problem with Zabbix polling which suggest either an ethernet socket open close problem or memory allocation problem.

    Zabbix polls three items, humidity, temperature and memory free using three configured items. Normally zabbix sends a temperature.read, humidity.read and memory.free string to port 10050 on the arduino etherten.

    The arduino reads the string and runs the appropriate code and responds with the appropriate value 20.10 [eg temp], 43.30 [eg humidty} and 1344 [eg memory free]. Mostly the arduino responds with the correct value, but I am seeing where a response contains a temp and memory free values which then cause an error in zabbix.

    I have implemented your changes to the ethernet library, but still have the problem.

    The arduino program logic is very simple/ Can you suggest any easy way to debug, as I am expecting to have to debug within the ethernet library.

    Thanks,

    Reply
    1. subethasoftware

      Scott, sorry I missed your comment. When I was tracking down this but, I was putting in prints inside of the Ethernet library code. It’s not system state driver code like an operating system would have, so it’s really not any different than other Arduino C code. If you want to drop me an email, I’d be happy to see if we could figure out what you are running in to.

      Reply
    1. Matt

      Sorry, this comment was supposed to be about some problem wordpress/html markup that was wrecking Allen’s modified code snippets, but I was having trouble posting comments until it finally work, but I had accidentally replaced my clipboard with that link instead of the actual comment.

      Reply
  11. Matt

    I want to say thanks Allen for the good work. These modifications needs to find their way into the official library.

    Reply
  12. Petr Stehlík

    Dear Allen,

    does your modification handle situation when two clients with different IP addresses connect to the server from the same ports? In other words, shouldn’t you be checking for source IP address as well? I’d think so, since a connection is identified by a quadruple: source IP, source port, dest IP, dest port. I know the probability of two connections having the same source port is small but it still exists so if the library is to be fixed then let’s do it properly.

    Will you submit your improvements to Github (where the ‘official’ place of the Ethernet library seems to be) or should I go ahead and help out with that?

    Thanks

    Reply
    1. Allen Huffman Post author

      Very good observation. I thought the existing code matched IP already, and I just added PORT to that mix. I thought it would work. I will have to test that.

      I do not know anything about getting items submitted back in to the official code base, and I have not looked at the 1.5 beta stuff to see if this has already been addressed. We would want to start there, and I expect my choice of where I put in the extra WizPro call to get that information may be more appropriate in another file. When I did this, it was my first time ever looking at this code. I really need to revisit it and check it.

      Reply
    2. Allen Huffman Post author

      By the way, I really do think this should be in the official code. I consider it a bug. This is the #1 most viewed thing on my site, with dozens of folks coming to this page every day since it got in the search engines.

      Reply
    3. Allen Huffman

      Petr – wow, I don’t see any checks for IP at all where I modified it. “Anything packet that comes in with this port I will accept”…??? I need to check the rest of the code and see if that check is done elsewhere.

      Reply
      1. Petr Stehlík

        I’ve been looking there and couldn’t see it either. Actually I must admit I am confused by the use of EthernetClient everywhere inside of EthernetServer so perhaps I am misreading the whole algorithm but yes, there are no IP address checks anywhere so I thought I’d ask you.

        Reply
  13. Petr Stehlík

    Allen, I’ve been thinking about it overnight and I believe your idea of running two servers on the same port is just plain wrong. You wouldn’t want to do that on a Linux server either because then you never know which server picks which client, among other things. What you want to achieve is that the server can accept more connections than one (basically up to the number of currently free sockets). What you’re currently doing (if I understand your code changes right) is kind of locking your telnet server instances to the Wiznet sockets hoping that first client gets first socket (first server instance) etc, and that’s weird and works just by coincidence, I am afraid.

    The approach described in the bug report #1260 on Github seems more reasonable – the server.available() simply returns another waiting client by attaching it to next free socket. Don’t you want to try that out? I have just run out of free Ethernet shields so I cannot try it ATM but I have already ordered new ones and will be able to test that soon (-ish, China delivery = 3 weeks).

    BTW, I have also followed the thread Bruce Durant posted year ago above in the comments and it’s also quite serious stuff that should be fixed ASAP. First, closing a socket with stuff left in RX buffer means losing it for good so you soon run out of free sockets unless you properly empty them first (scary!). Second, closing UDP connection in the middle of your program and then trying to re-open it causes huge issues with TCP and UDP stepping on each other’s shoes (=using the same socket) and basically corrupting the communication and even leading to hard freezes (due to other bugs in the implementation). It’s like TCP doesn’t respect UDP used sockets, or vice versa, not sure at first glance. But definitely a bad thing.

    Reply
    1. admin

      You are correct. My wording is sloppy. The WizNet works differently than standard socket() libraries. You truly can have all four of the WizNet slots listening on the same port, which is not possible with a BSD-style socket library where the bind() fails if you try to bind to a port already in use.

      In BSD-style sockets, an application will create a socket(), then bind() it to a specific port. The server then will listen() for a connection. At the accept(), the application will block waiting for a connection (unless using non-blocking), and when a connection is present, accept() returns a path to the client. The server then read/writes to that path and communicates with the remote connection. Internally, this connection moved to a different port, and the remote connection is actually reading/writing data to the new port. The main server can go back and wait for more connections on the original port.

      The WizNet 5100 hardware uses a simple way to do this. You have four connections available, each with their own buffer. You place an IP and PORT in one of those four slots. Any traffic that comes in with an IP and PORT that matches will go in to that buffer. I could set slot 1 to listen for “200.10.20.30:2000” and slot 2 to listen for “100.10.20.30:2000”. Packets from either IP would go to the appropriate slot’s buffer. (Simplified. It actually has remote port, local port, IP, and maybe some other fields.)

      The other part of WizNet is how it establishes a connection. Initially, you basically just have a port assigned to a slot and the IP is clear (I forget what, maybe 0.0.0.0 or 255.255.255.255 or something). If a packet comes in from a new IP to that port, WizNet will assign it to that slot. Until the connection is closed, any traffic from that IP to that port will go to that buffer. (I forget the details, but there is more to it — it checks all four slots to see if one is already matching.)

      This lets WizNet achieve the same type of result, but in a very different way. The WizNet is used in many industries, and I believe there are socket()-style libraries for it that simulate the calls.

      I am unaware of the TCP/UDP problems. It sounds like there is much more wrong with this Ethernet implementation that just the one item I was concerned with.

      What should we do? Feel free to e-mail me if you would like to discuss. Maybe we can design a new implementation :)

      Reply
      1. Petr Stehlík

        OK, that explains a bit, thank you.
        BTW, you might find interesting that a project creating a web server for Arduino/Wiznet slowly developed their own library. Last thing I heard was about adding UDP there. Don’t have a link handy (read about that somewhere in Arduino forum) but will try to find it and compare the sources. They might have designed it in a way that does not have the shortcomings you’ve encountered with the stock library.

        Reply
  14. Matt

    I have been using Allen’s modification for a few weeks now. I initialize 4 server and 4 client instances and then bind them when a new connection comes in.

    in variable declaration:
    EthernetServer server[4] = {
    EthernetServer(serverPort),
    EthernetServer(serverPort),
    EthernetServer(serverPort),
    EthernetServer(serverPort)
    };
    EthernetClient client[4] = {};

    in the loop:
    for (byte i=0;i<4;i++){
    if (server[i].available() && !client[i].connected()){
    client[i] = server[i].available();

    I then also use a few other variables to track open connections, connection count etc.

    It was been mostly working pretty good. I have had to implement an auto-reset check into the Arduino as the ethernet interface seems to hang randomly, even when there's only one connection being opened at a time. I have been running two Arduinos, one with the stock library and one with the modified library. They aren't quite the same program because of how I handle the modded library but they are trying to accomplish the same thing and the unmodified does not hang. Sometimes it's enough to reinitialize the ethernet IP, MAC and servers but sometimes I have to reset the Arduino even though it is still outputting debug messages, so the Arduino doesn't hang but something quits working.

    But allowing multiple simultaneous socket connections allows me to remotely monitor the debug messages on one connection while my server requests data updates on another connection.

    Reply
    1. Allen Huffman Post author

      Matt, did you get a reset check implemented? The Arduinos (or at least the Teensy 2.0) have a watchdog timer than can reboot the system in case of a lockup. I use that in my I/O boxes I build just in case. If the lockup is just the Ethernet Shield, I suppose it would be easier just to do it in software.

      Reply
      1. Matt

        It’s been a while now since I last worked on this. I now use USR-TCP232T modules instead of W5100 (or similar) chips. This unloads some of the Arduino’s flash/ram usage and the USR modules seem to work quite reliably. For wireless, I then use the USR-WIFI232 modules.

        Reply
    1. Allen Huffman Post author

      I finally had a chance to look at their updates. It does not look like it handles multiple connections on the same port, either. I think these libraries are mostly designed for outgoing connections, or only having one user connect at a time for incoming.

      Reply
      1. Glen Fraser

        Hi Allen, I used the 8 connection one to have a quick play with. I found I could with 8 machines connect with my Delphi app run on all 8 to the lan module. Depending on how I addressed it from memory depended on if it sent the message to all 8 or just the machine that sent the info. When I tried to connect the 9th machine it refused. Which is what I would expect seeing as I had used all 8 sockets….. I didn’t go any further at present as I needed to decode the strings received at the arduino and also how to decode a port when set high or low on the arduino and send the message to my program. I hope to be able to site down and play a bit more with this soon…

        Reply
  15. Dave Harper

    Thank you so much for this post. I am in the early stages of a new revision of a project that previously used an Atmel AT91SAM7X512 (with embedded EMAC) and ran lwIP. Having recently discovered WIZnet (and specifically the W5500 with 8 sockets), it looked like this would provide a much easier approach to implementing the Ethernet connection. Unfortunately, I was having serious problems trying to resolve how to map the traditional socket implementation approach onto the WIZnet hardware. I had been thinking along the lines of dedicating one socket to be the listener and, when a browser connection was made, the embedded web server would respond with something like “meet me over on Port ‘xxxx’ and we’ll resume there”, where “Port xxxx” would be one of the remaining sockets currently in listening mode. It would then close the connection and continue listening on port 80 for other browser connection attempts. The problem with this approach is it simply moves a difficult problem from the W5500 side of things to the browser code side of things. For the past several evenings I have been searching the web to see if anyone else was attempting to do what I was trying to do and last night I stumbled across this web page. My (incorrect) assumption had been that each socket in the W5500 would require a unique port value. You made the statement, “The Wiznet hardware is fine even with all four of it’s sockets listening to the same port. It tracks the actual connection internally.” Suddenly everything made sense and the path to easily implement multiple browser connections seems very straightforward. Many thanks for sharing this information – you’ve saved me a bunch of time. BTW, I’m currently doing my development with a SAM4S-EK development board with an attached WIZnet W550io board using Atmel Studio. So far this seems to be a much better approach than the Eclipse based toolset from the previous project.

    Regards,
    Dave

    Reply
    1. Allen Huffman Post author

      Thanks for the note, Dave. I thought I found some references to a BSD-style socket() interface for these chips, but since it would bulk up the library I didn’t do much digging in to it. Good luck on your project! I am hopeful of having time this Spring to get back to work on mine.

      Reply
    2. Allen Huffman Post author

      Check the article for a link to a Telnet example on the Arduino playground. The implementer talks directly to the Wiznet chip so he has one socket listening, but then handles I/O based on slots 1-X where the data is. Neither the native Arduino approach (with my hacks), or this approach, is really ideal, but it might be worth a look.

      Reply
  16. Pingback: Configuring the TP-LINK TL-WR702N nano router for Arduino | Sub-Etha Software

  17. Ruud B.

    Hi Allen. Your findings where a blessing for my problem…I realised there is somthing going on..and it was not ‘me’. However, I’m tryin this now on the recent version of the arduino software and it seems it does not react on the client1.available(). Are there more people having the same problem? Do you by any chance have a little spare time to have a look at this….because of what I find on the net…you are the guru concerning this topic. I dont understand that this is not seen as a bug or not solved yet…pitty because it is causing a lot of frustration.
    Hee thanks for the guidance and advice.
    Regards,
    Ruud

    Reply
    1. Allen Huffman Post author

      The Arduino software has been updated several times since that post, and I just noticed a 1.60 or something that my Mac Update Desktop software downloaded last night. I will try to set it up and take a look this week.

      Reply
  18. Ruud B.

    Hi Allen, Great! Thanks for spending the time. I will try agian this with the new version immediatly. I supose I must have missed something.
    The link to the zip is not working yet, Can you check that one.
    I will return with the result.
    Thanks again!
    Ruud

    Reply
  19. Ruud B.

    Allen, The link in the text at the top is working. its only the one in the response that seem to go wrong. Anyways I got it :-) thanks

    Reply
  20. Pingback: Web browser accessing Arduino data « Coert Vonk

  21. Pingback: jsfiddle, JSON-P and Arduino « Coert Vonk

  22. Gene

    Thank You Sir,

    There are still many issues with the code, The console input handling is well below acceptable, the ClientList class should use some sort of GUID for client connection look up, there is no hooks for adding commands and zero security.
    When I started writing the code, I had forgotten that the EthernetClient class did not expose the remoteIP and remotePort (which I believe to be necessary properties) and I had to do some googling to find a solution that did not require modifying the original library. I had copied the lib to my user libs tree and made many modifications to to it (added hostname support to the DHCP request, changed some of the order of execution of the listening loop due to issues with the web server stalling when the clients browser would not pause when requesting the pages assorted external files when the page contained ~20 or more images..

    Mostly I enjoy spreading what I have learned.
    I will stop my rambling and move on, happy coding to you sir and have a great day..

    Gene

    Reply
  23. FERET Philippe

    Hi Every Body
    I take the “train running” like we say in french.
    Now Ethernet rev 3 shield is obsolte new Ethernet v2…
    Is there any need with the new library coming with v2 with multi session ?
    Thks in advance
    Philippe

    Reply
  24. Pingback: Web browser accessing Arduino data « Coert Vonk

Leave a Reply