Go Down

Topic: WiFi & Sockets (Read 638 times) previous topic - next topic

RayLivingston

I'm trying to get very basic sockets communications going between two 8266 WiFi nodes.  It works sporadically.  There seems to be no real problem with the basic configuration of the two 8266 nodes, as the setup code is all copied from my working application that has 7 8266s all talking to each other over a tree-structured network where three of the 8266s are both APs and Stations, the rest are just Stations.

But, with the below code, most of the time the "server" messages do make it to the "client" correctly, and they are "reflected" back, but rarely make it back to the server.

What am I doing wrong here?  The SERVER define controls whether the code is built for the server node or client node.  I am running both on NODEMCUs.

Code: [Select]

#include <ESP8266WiFi.h>

#define SERVER

#if defined(SERVER)
WiFiServer server = WiFiServer(8000);

#endif

uint8_t Cnt = 123;

uint8_t State = 0;

WiFiClient client = WiFiClient();

IPAddress Netmask = IPAddress(255, 255, 255, 0);

char *STASSID = "TP-LINK_A47DC2";
char *STAPass = "79517515";
IPAddress STAGatewayIP = IPAddress(10, 0, 0, 1);
IPAddress STAIP = IPAddress(10, 0, 0, 50);

char *APSSID = "WiFiNetwork";
char *APPass = "WiFiPassword";
IPAddress APIP = IPAddress(192, 168, 0, 1);

IPAddress ClientIP = IPAddress(192, 168, 0, 2);


char s[80];
int i = 0;
uint32_t timer = 0;

#if defined(SERVER)
void ServerSetup()
{
boolean success = false;

while (!success)
{
// Disconnect, if connected
WiFi.disconnect();

// Set Mode
if (!(success = WiFi.mode(WiFiMode_t::WIFI_AP_STA)))
continue;

// Configure STA
if (!(success = WiFi.config(STAIP, STAGatewayIP, Netmask, STAGatewayIP)))
continue;

// Configure AP
if (!(success = WiFi.softAPConfig(APIP, STAGatewayIP, Netmask)))
continue;

// Start/Connect AP + STA
WiFi.persistent(true);
if (!(success = WiFi.setAutoConnect(true)))
continue;

if (!(success = WiFi.begin(STASSID, STAPass)))
continue;

if (!(success = WiFi.setAutoReconnect(true)))
continue;

if (!(success = WiFi.softAP(APSSID, APPass, 1)))
continue;
}

server.begin();

Serial.printf("\n\nServer Ready\n");
}


void ServerLoop()
{
switch (State)
{
case 0:
client = server.available();
if (client)
{
Serial.printf("Server: Wrote: %03d ", Cnt);
client.printf("\r\n%03d\r\n", Cnt);
timer = millis();
State = 1;
}
break;

case 1:
client = server.available();
while (client.available())
{
char c = client.read();
if (c == '\r')
continue;
else if (c == '\n')
{
if (i > 0)
{
int val = atoi(s);
Serial.printf("Read: %03d => ", val);
if (val == Cnt)
{
Serial.printf("Match\n");
Cnt++;
State = 0;
}
else
{
Serial.printf("No Match\n");
Cnt++;
client.stop();
State = 0;
}
}
i = 0;
s[i] = '\0';
}
else
{
s[i++] = c;
s[i] = '\0';
Serial.print(c);
}
}
if (millis() - timer > 3000)
{
client.stop();
Serial.printf("Timeout\n");
Cnt++;
State = 0;
}
break;
}
}

#else
void ClientSetup()
{
boolean success = false;

while (!success)
{
// Disconnect, if connected
WiFi.disconnect();

// Set Mode
if (!(success = WiFi.mode(WiFiMode_t::WIFI_STA)))
continue;

// Configure STA
if (!(success = WiFi.config(ClientIP, APIP, Netmask, APIP)))
continue;

WiFi.persistent(true);
if (!(success = WiFi.setAutoConnect(true)))
continue;

// Connect STA
if (!(success = WiFi.begin(APSSID, APPass)))
continue;

if (!(success = WiFi.setAutoReconnect(true)))
continue;
}

client.connect(APIP, 8000);

Serial.printf("\n\nClient Ready\n");
}


void ClientLoop()
{
if (!client.connected())
{
//client.stop();
client.connect(APIP, 8000);
}
else
{
char s[80];
int i = 0;
while (client.available())
{
char c = client.read();
if (c == '\r')
continue;
else if (c == '\n')
{
if (i > 0)
{
int val = atoi(s);
Serial.printf("Client: Wrote: %03d\n", val);
client.printf("\r\n%03d\r\n", val);
}
i = 0;
s[i] = '\0';
}
else
{
s[i++] = c;
s[i] = '\0';
}
}
}
}
#endif


void setup()
{
Serial.begin(115200);

#if defined(SERVER)
ServerSetup();
#else
ClientSetup();
#endif
}



void loop()
{
#if defined(SERVER)
ServerLoop();
#else
ClientLoop();
#endif
}


Regards,
Ray L.

Juraj

I am not an expert on how the esp wifi library is implemented, but I think a server can have more clients and available returns one of them.

you send data over 'socket', the client esp responses on that 'socket', but you get some client from the server with available. by chance it is the same, but it can be some other. some old not closed. you do not test client.connected() and you do not close 'sockets' disconnected by client

RayLivingston

I think you're right, but I can't find a single example that makes clear exactly how to do this correctly.  I want to be able to send and receive data between two nodes.  AFAICT, the client side is pretty straight-forward - if not connected, do a client.connect.  if client.available is true, read data, otherwise, write data.  But the server side is not at all clear.  How do I know WHEN to do a server.available()?  WHEN is the connection closed?  HOW do I make the connection persist, since I need to be sending data in both directions fairly often (at least once/second).  The problem I see most often is the server thinks there is a connection, and sends data, but the client never gets it.

This should not be difficult, but the examples I've found are all so trivial, they are of no help whatsoever.

Regards,
Ray L.

Juraj

#3
Dec 05, 2017, 06:31 pm Last Edit: Dec 05, 2017, 07:14 pm by Juraj
client.connected(), tests the state of the socket. works for server side socket too. or you can use state(). ESTABLISHED is the right one.

you should hold the client object if you want read the answer from the client. the server is there only to initiate the connection. then the server side and client side sockets are simply connected sockets.

to distinguish clients, client object has
Code: [Select]

  IPAddress remoteIP();
  uint16_t  remotePort();
  IPAddress localIP();
  uint16_t  localPort();

RayLivingston

If there's a way to make this work reliably, it is eluding me.  I've spent hours trying dozens of different configurations of the code, and haven't found anything that works more than sporadically.  It seems to me, the basic logic should be:

Server Side:
Code: [Select]

if (!client.connected())
    client = server.available();
else if (client)
{
    client.print("Something");
    while (client.available()
        Serial.print((char)client.read());
}


Client Side:
Code: [Select]

if (!client.connected())
    client.connect(ssid, password);
else
{
    client.print("Something");
    while (client.available())
        Serial.print((char)client.read());
}
[\code]

But, that logic simply does not work.  It may sporadically get some data through, but not often.

It seems to me that before doing a write/print on a client, client.connected() should be verified, as the operation will obviously fail if the client is NOT connected.  But reads can be done anytime, as the client object may contain valid data even after the connection has closed.  Of course, even checking client.connected() immediately before the write, there is no guarantee the connection won't be closed a uSec later.  So, I just don't see how you can ever be sure the data actually got out.

Surely, somewhere, there is a good example of how to do this right, and not just trivial examples that transmit a single message in one direction, then close the socket?

Regards,
Ray L.

RayLivingston

The more I dig into this, the less sense it makes....  I've backed off to about the most trivial example I could think of - the client makes the connection, sends some data, then closes the connection.  The result is....  confusing.  First, here is the code:

Code: [Select]

#include <ESP8266WiFi.h>

//#define SERVER

#if defined(SERVER)
WiFiServer server = WiFiServer(8888);

#endif

WiFiClient client = WiFiClient();

IPAddress Netmask = IPAddress(255, 255, 255, 0);

char *STASSID = "TP-LINK_A47DC2";
char *STAPass = "79517515";
IPAddress STAGatewayIP = IPAddress(10, 0, 0, 1);
IPAddress STAIP = IPAddress(10, 0, 0, 50);

char *APSSID = "WiFiNetwork";
char *APPass = "WiFiPassword";
IPAddress APIP = IPAddress(192, 168, 0, 1);

IPAddress ClientIP = IPAddress(192, 168, 0, 2);


char s[80];
int i = 0;
uint32_t timer = 0;

#if defined(SERVER)
void ServerSetup()
{
boolean success = false;

while (!success)
{
// Disconnect, if connected
WiFi.disconnect();

// Set Mode
if (!(success = WiFi.mode(WiFiMode_t::WIFI_AP_STA)))
continue;

// Configure STA
if (!(success = WiFi.config(STAIP, STAGatewayIP, Netmask, STAGatewayIP)))
continue;

// Configure AP
if (!(success = WiFi.softAPConfig(APIP, STAGatewayIP, Netmask)))
continue;

// Start/Connect AP + STA
WiFi.persistent(true);
if (!(success = WiFi.setAutoConnect(true)))
continue;

if (!(success = WiFi.begin(STASSID, STAPass)))
continue;

if (!(success = WiFi.setAutoReconnect(true)))
continue;

if (!(success = WiFi.softAP(APSSID, APPass, 6)))
continue;
}

server.begin();

pinMode(16, OUTPUT);

Serial.printf("\n\nServer Ready\n");
}


void ServerLoop()
{
if (!client.connected())
{
digitalWrite(16, HIGH);
client = server.available();
}
else if (client.connected())
{
digitalWrite(16, LOW);
while (client.available())
{
Serial.print((char)client.read());
}
}
}

#else

void ClientSetup()
{
boolean success = false;

while (!success)
{
// Disconnect, if connected
WiFi.disconnect();

// Set Mode
if (!(success = WiFi.mode(WiFiMode_t::WIFI_STA)))
continue;

// Configure STA
if (!(success = WiFi.config(ClientIP, APIP, Netmask, APIP)))
continue;

WiFi.persistent(true);
if (!(success = WiFi.setAutoConnect(true)))
continue;

// Connect STA
if (!(success = WiFi.begin(APSSID, APPass)))
continue;

if (!(success = WiFi.setAutoReconnect(true)))
continue;
}
client.setTimeout(5000UL);

pinMode(16, OUTPUT);

Serial.printf("\n\nClient Ready\n");
}


void ClientLoop()
{
static int32_t last = 0;

if (!client.connected())
{
digitalWrite(16, HIGH);
if (client.connect(APIP, 8888))
{
digitalWrite(16, LOW);
uint32_t delta = millis() - last;
client.printf("Hello %lu\n", delta);
Serial.printf("Wrote %lu\n", delta);
last = millis();
delay(10);
client.stop();
}
}
}
#endif


void setup()
{
Serial.begin(115200);

#if defined(SERVER)
ServerSetup();
#else
ClientSetup();
#endif
}



void loop()
{
#if defined(SERVER)
ServerLoop();
#else
ClientLoop();
#endif
}


The LED on each NODEMCU is lit whenever the client.connected() == true.  The client does a connect(), sends a message, prints that same message to its console, waits 1 mSec, then does a client.stop().  The server waits for a connection, prints whatever data it gets to its console.

What I see is, at times, it behaves as expected - the LEDs blink more or less in unison, and the same data is displayed on both consoles.  But, that only last a few seconds at most, then BOTH LEDs get stuck ON, the latest message is displayed on the server, but NOT on the client.  After some period of time, as much as 1-15 seconds, the LEDs go out, the message finally appears on the client console.  Sometimes it will do another burst of correct transfers, other times BOTH LEDS go out for several seconds.  Overall throughput is abysmal, averaging single digits of packets per second.  Getting stuck with the LEDs ON, and the client message NOT being displayed indicates the client.print() is taking a looooooooong time to execute.  Why??  Both 8266s see a valid connection, so how is it getting stuck like that??

Regards,
Ray L.

RayLivingston

Interestingly, when the client.print call "hangs", it hangs for exactly 5 seconds every time.  In most cases, for some period of time after the hang, it continues to hang on subsequent cycles, with the server never receiving any data, despite seeing a valid connection the whole time.  Eventually, it all starts working again.

This is completely unusable as it is.  Who could possibly use a WiFi adaptor that goes off-line for 5 or more seconds every few seconds?  There MUST be something I'm doing wrong, but d@mned if I can see what it is, and the problem seems to be happening in the bowels of the ESP libraries....

Regards,
Ray L.

RayLivingston

This is interesting/disconcerting....  I changed the code so the softAP is forced to channel 11, and it now seems to be working well, with out the long "stalls".  This suggest a problem with interference, but it was still failing on channels 1 and 6 with my TPLINK AP turned off.  I don't know what to make of this...

Regards,
Ray L.

Juraj

you could try core 2.4 rc2. I had strange connection problems with rc1 and with rc2 it seems stable.

RayLivingston

I'm using 2.2.0.  I started with 2.3.0, and found it has SERIOUS problems.  Where can I get 2.4?

Switching channels does seem to resolve my problems, but I don't know why, since there are NO other networks here when my router is turned off.  Channel 1 sucks.  Channel 6 is only slightly better.  Channel 11 works great.  Most higher channels seem to work well.


Regards,
Ray L.

Juraj

add https://github.com/esp8266/Arduino/releases/download/2.4.0-rc2/package_esp8266com_index.json in IDE properties

RayLivingston

Unfortunately, that seems to have completely screwed me. I can no longer build ANY 8266 code.  The libraries are installed, and the boards all show up in the Boards menu, but all builds fail:

Arduino: 1.8.4 (Windows 10), Board: "NodeMCU 0.9 (ESP-12 Module), 80 MHz, 115200, 4M (3M SPIFFS)"

E:\Users\RayL\Documents\AppData\Arduino\arduino-1.8.4\arduino-builder -dump-prefs -logger=machine -hardware E:\Users\RayL\Documents\AppData\Arduino\arduino-1.8.4\hardware -hardware C:\Users\RayL\AppData\Local\Arduino15\packages -tools E:\Users\RayL\Documents\AppData\Arduino\arduino-1.8.4\tools-builder -tools E:\Users\RayL\Documents\AppData\Arduino\arduino-1.8.4\hardware\tools\avr -tools C:\Users\RayL\AppData\Local\Arduino15\packages -built-in-libraries E:\Users\RayL\Documents\AppData\Arduino\arduino-1.8.4\libraries -libraries C:\Users\RayL\Documents\Arduino\libraries -fqbn=esp8266:esp8266:nodemcu:CpuFrequency=80,UploadSpeed=115200,FlashSize=4M3M -ide-version=10804 -build-path C:\Users\RayL\AppData\Local\Temp\arduino_build_137549 -warnings=none -build-cache C:\Users\RayL\AppData\Local\Temp\arduino_cache_68001 -prefs=build.warn_data_percentage=75 -prefs=runtime.tools.xtensa-lx106-elf-gcc.path=C:\Users\RayL\AppData\Local\Arduino15\packages\esp8266\tools\xtensa-lx106-elf-gcc\1.20.0-26-gb404fb9-2 -prefs=runtime.tools.mkspiffs.path=C:\Users\RayL\AppData\Local\Arduino15\packages\esp8266\tools\mkspiffs\0.1.2 -prefs=runtime.tools.esptool.path=C:\Users\RayL\AppData\Local\Arduino15\packages\esp8266\tools\esptool\0.4.8 -verbose C:\Users\RayL\Documents\Arduino\sketch_dec06a\sketch_dec06a.ino

Board nodemcu (platform esp8266, package esp8266) is unknown

Error compiling for board NodeMCU 0.9 (ESP-12 Module).

Regards,
Ray L.

Juraj

sorry. did you try setting board parameters again in Tools menu after upgrading esp core package?

RayLivingston

I ended up having to re-install the IDE, then the 8266 package.  No clue what went wrong the first time, but I couldn't figure out how to fix it.  It's working fine now.

Regards,
Ray L.

Juraj

end you returned to 2.2 or you try the 2.4 rc2?

Go Up