I have an application where we have built several ModBus slaves using Arduino Megas with Wiznet's ethernet module. They work fine although they do lock up from time to time. My question though has to do with multiple clients connecting to the board at the same time and sending essentially the same commands.
How does the Ethernet Shield know when one command is finished (to one client) and the next one begins? If two are sent one after the other, what is my "client.available()" going to tell me? Will it be the total number of bytes from BOTH clients or just the first one? If it's just the first one, when my loop comes around again and does "client = server.available()" again, will it then give me the other packet (that was sent from a different machine)?
Is there anyway to gain access to the tcp/ip info (like source ip/port number) from within the current library?
Thanks for any info you can provide.
len morgan
Colorado River Municipal Water District
The client.available() call will return the number of characters currently in the receive buffer for that socket. Each connection will get its own socket, so it only shows the number of characters for each connection request.
You might want to identify each client by either the page the client requests or variables sent by the client.
When you are talking about a "socket" here, are you saying that the return value from "server.available()" is a socket (rather than a Client object)? That would clear things up a little for me if that were the case.
Also, the clients are not visiting "pages" or sending variables. This is a ModBus/TCP conversation(s) so I don't have access to who sent the request or issued the command. That is the second part of my original post: Is the source IP and/or port number available from the library anywhere? I get back a Client object (which appears to be a socket #) when the connection is opened, but I haven't seen a function (like client.ipsourceaddress() or client.portnumber()) in the library. If I wanted this information, would I need to modify the library to create these functions?
My question though has to do with multiple clients connecting to the board at the same time and sending essentially the same commands.
Below is some meta refresh code that you can test multiple browser client connections. You can change the meta refresh value from 2 to 0 to attempt the fastest connections to the server, and open multiple browser instances of the page to see how well they compete for the server data updates. There is also a client.getRemoteIP(rip); function available that can get the ip address of the client being served.
// zoomkat meta refresh server test code
// arduino IDE 1.0
// for W5100 ethernet shield
// the IP address will be dependent on your local network/router
// port 80 is default for HTTP, but can be changed as needed
// use IP address like http://192.168.1.102:84 in your brouser
// or http://zoomkat.no-ip.com:84 with dynamic IP service
// use the \ slash to escape the " in the html
// meta refresh set for 2 seconds
#include <SPI.h>
#include <Ethernet.h>
int x=0; //set refresh counter to 0
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,1,102); // ip in lan
EthernetServer server(84); //server is using port 84
void setup()
{
// start the server
Ethernet.begin(mac, ip);
server.begin();
}
void loop()
{
// listen for incoming clients
EthernetClient client = server.available();
if (client) {
while (client.connected()) {
if (client.available()) {
char c = client.read();
// see if HTTP request has ended with blank line
if (c == '\n') {
// send a standard http response header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println();
//meta-refresh page every 2 seconds
x=x+1; //page upload counter
client.println("<HTML>");
client.print("<HEAD>");
client.print("<meta http-equiv=\"refresh\" content=\"2\">");
client.print("<TITLE />Zoomkat's meta-refresh test</title>");
client.print("</head>");
client.println("<BODY>");
client.print("Zoomkat's meta-refresh test IDE 1.0");
client.println("
");
client.print("page refresh number ");
client.println(x); //current refresh count
client.println("
");
client.println("
");
client.print("Zoomkat's arduino analog input values:");
client.println("
");
client.println("
");
// output the value of each analog input pin
for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
client.print("analog input ");
client.print(analogChannel);
client.print(" is ");
client.print(analogRead(analogChannel));
client.println("
");
}
break;
client.println("</BODY>");
client.println("</HTML>");
}
}
}
// give the web browser time to receive the data
delay(1);
// close the connection:
client.stop();
}
}
I get back a Client object (which appears to be a socket #) when the connection is opened, but I haven't seen a function (like client.ipsourceaddress() or client.portnumber()) in the library. If I wanted this information, would I need to modify the library to create these functions?
Unfortunately, you need to modify the library to get that data.
best I can tell from going through the source is there is no direct api available to determine the ip address of the cilent as that is hidden by the wiznet chip and the only interface to arduino is via SPI and you only get one of 4 sockets the server is connected to and if there is data available in the receive buffer.
you can try adding this to EthernetClient.cpp (and the corresponding entry in .h)
To test these, you can use webserver sample, and add these lines after server.available() is true
IPAddress addr = client.destIp();
Serial.print("Client IP address: ");
Serial.println(addr);
uint16_t port = client.destPort();
Serial.print("Client port is ");
Serial.println(port);
I am attaching the files as well. Just backup and replace the files in Ethernet libraries folder.
Some server test code that captures the client ip address.
//zoomkat 12-8-11
//simple button GET with iframe code
//for use with IDE 1.0
//open serial monitor to see what the arduino receives
//use the \ slash to escape the " in the html
//address will look like http://192.168.1.102:84 when submited
//for use with W5100 based ethernet shields
#include <SPI.h>
#include <Ethernet.h>
byte rip[4];
//byte rip[] = {0,0,0,0};
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = { 192, 168, 1, 102 }; // ip in lan
byte gateway[] = { 192, 168, 1, 1 }; // internet access via router
byte subnet[] = { 255, 255, 255, 0 }; //subnet mask
EthernetServer server(84); //server port
String readString;
//////////////////////
void setup(){
pinMode(4, OUTPUT); //pin selected to control
//start Ethernet
Ethernet.begin(mac, ip, gateway, subnet);
server.begin();
//enable serial data print
Serial.begin(9600);
Serial.println("server LED test 1.0"); // so I can keep track of what is loaded
}
void loop(){
// Create a client connection
EthernetClient client = server.available();
if (client) {
while (client.connected()) {
if (client.available()) {
char c = client.read();
//read char by char HTTP request
if (readString.length() < 100) {
//store characters to string
readString += c;
//Serial.print(c);
}
//if HTTP request has ended
if (c == '\n') {
///////////////
Serial.println(readString); //print to serial monitor for debuging
client.getRemoteIP(rip);
for (int bcount= 0; bcount < 4; bcount++)
{
Serial.print(rip[bcount], DEC);
if (bcount<3) Serial.print(".");
}
Serial.println();
//now output HTML data header
if(readString.indexOf('?') >=0) { //don't send new page
client.println("HTTP/1.1 204 Zoomkat");
client.println();
client.println();
}
else {
client.println("HTTP/1.1 200 OK"); //send new page
client.println("Content-Type: text/html");
client.println();
client.println("<HTML>");
client.println("<HEAD>");
client.println("<TITLE>Arduino GET test page</TITLE>");
client.println("</HEAD>");
client.println("<BODY>");
client.println("<H1>Zoomkat's simple Arduino button</H1>");
client.println("<a href=\"/?on\" target=\"inlineframe\">ON</a>");
client.println("<a href=\"/?off\" target=\"inlineframe\">OFF</a>");
//client.println("<IFRAME name=inlineframe src=\"res://D:/WINDOWS/dnserror.htm\" width=1 height=1\">");
client.println("<IFRAME name=inlineframe style=\"display:none\" >");
client.println("</IFRAME>");
client.println("</BODY>");
client.println("</HTML>");
}
delay(1);
//stopping client
client.stop();
///////////////////// control arduino pin
if(readString.indexOf("on") >0)//checks for on
{
digitalWrite(4, HIGH); // set pin 4 high
Serial.println("Led On");
}
if(readString.indexOf("off") >0)//checks for off
{
digitalWrite(4, LOW); // set pin 4 low
Serial.println("Led Off");
}
//clearing string for next read
readString="";
}
}
}
}
}