use static list of client connections in socket server

This commit is contained in:
andreas 2021-10-25 19:46:53 +02:00
parent c893025cd3
commit 8c02b21277
2 changed files with 99 additions and 41 deletions

View File

@ -51,15 +51,36 @@ class GwClient{
GwBuffer *buffer;
GwLog *logger;
int overflows;
String remoteIp;
private:
Writer *writer;
Writer *writer=NULL;
public:
GwClient(wiFiClientPtr client,GwLog *logger){
this->client=client;
this->logger=logger;
buffer=new GwBuffer(logger);
overflows=0;
if (client != NULL){
writer=new Writer(client);
remoteIp=client->remoteIP().toString();
}
}
void setClient(wiFiClientPtr client){
this->client=client;
buffer->reset();
overflows=0;
if (writer) delete writer;
writer=NULL;
if (client){
writer=new Writer(client);
remoteIp=client->remoteIP().toString();
}
else{
remoteIp=String("---");
}
}
bool hasClient(){
return client != NULL;
}
~GwClient(){
delete writer;
@ -68,7 +89,7 @@ class GwClient{
if (len == 0) return true;
size_t rt=buffer->addData(data,len);
if (rt < len){
LOG_DEBUG(GwLog::LOG,"overflow on %s",client->remoteIP().toString().c_str());
LOG_DEBUG(GwLog::LOG,"overflow on %s",remoteIp.c_str());
overflows++;
return false;
}
@ -78,12 +99,16 @@ class GwClient{
return buffer->usedSpace() > 0;
}
GwBuffer::WriteStatus write(){
if (! writer) {
LOG_DEBUG(GwLog::LOG,"write called on empty client");
return GwBuffer::ERROR;
}
GwBuffer::WriteStatus rt=buffer->fetchData(writer,false);
if (rt != GwBuffer::OK){
LOG_DEBUG(GwLog::DEBUG+1,"write returns %d on %s",rt,client->remoteIP().toString().c_str());
LOG_DEBUG(GwLog::DEBUG+1,"write returns %d on %s",rt,remoteIp.c_str());
}
if (writer->timeOut ){
LOG_DEBUG(GwLog::LOG,"timeout on %s",client->remoteIP().toString().c_str());
LOG_DEBUG(GwLog::LOG,"timeout on %s",remoteIp.c_str());
return GwBuffer::ERROR;
}
return rt;
@ -94,9 +119,14 @@ class GwClient{
GwSocketServer::GwSocketServer(const GwConfigHandler *config,GwLog *logger){
this->config=config;
this->logger=logger;
maxClients=config->getInt(config->maxClients);
clients=new gwClientPtr[maxClients];
for (int i=0;i<maxClients;i++){
clients[i]=gwClientPtr(new GwClient(wiFiClientPtr(NULL),logger));
}
}
void GwSocketServer::begin(){
server=new WiFiServer(config->getInt(config->serverPort),config->getInt(config->maxClients));
server=new WiFiServer(config->getInt(config->serverPort),maxClients);
server->begin();
logger->logString("Socket server created, port=%d",
config->getInt(config->serverPort));
@ -107,45 +137,62 @@ void GwSocketServer::loop()
{
WiFiClient client = server->available(); // listen for incoming clients
if (client){
if (client)
{
logger->logString("new client connected from %s",
client.remoteIP().toString().c_str());
fcntl(client.fd(), F_SETFL, O_NONBLOCK);
gwClientPtr newClient(new GwClient(wiFiClientPtr(new WiFiClient(client)),logger));
clients.push_back(newClient);
bool canHandle = false;
for (int i = 0; i < maxClients; i++)
{
if (!clients[i]->hasClient())
{
clients[i]->setClient(wiFiClientPtr(new WiFiClient(client)));
logger->logString("set client as number %d", i);
canHandle = true;
break;
}
}
if (!canHandle)
{
logger->logDebug(GwLog::ERROR, "no space to store client, disconnect");
client.stop();
}
}
//sending
for (auto it = clients.begin(); it != clients.end();it++){
GwBuffer::WriteStatus rt=(*it)->write();
if (rt == GwBuffer::ERROR){
LOG_DEBUG(GwLog::ERROR,"write error on %s, closing",(*it)->client->remoteIP().toString().c_str());
(*it)->client->stop();
for (int i = 0; i < maxClients; i++)
{
gwClientPtr client = clients[i];
if (!client->hasClient())
continue;
GwBuffer::WriteStatus rt = client->write();
if (rt == GwBuffer::ERROR)
{
LOG_DEBUG(GwLog::ERROR, "write error on %s, closing", client->remoteIp.c_str());
client->client->stop();
}
}
for (auto it = clients.begin(); it != clients.end();it++)
for (int i = 0; i < maxClients; i++)
{
if ((*it) != NULL)
gwClientPtr client = clients[i];
if (!client->hasClient())
continue;
if (!client->client->connected())
{
if (!(*it)->client->connected())
{
logger->logString("client disconnect");
(*it)->client->stop();
clients.erase(it);
logger->logString("client %d disconnect %s", i, client->remoteIp.c_str());
client->client->stop();
client->setClient(NULL);
}
else
{
while ((*it)->client->available())
while (client->client->available())
{
char c = (*it)->client->read();
char c = client->client->read();
//TODO: read data
}
}
}
else
{
it = clients.erase(it); // Should have been erased by StopClient
}
}
}
void GwSocketServer::sendToClients(const char *buf){
int len=strlen(buf);
@ -155,11 +202,14 @@ void GwSocketServer::sendToClients(const char *buf){
len++;
buffer[len]=0x0a;
len++;
for (auto it = clients.begin() ; it != clients.end(); it++) {
if ( (*it) != NULL && (*it)->client->connected() ) {
bool rt=(*it)->enqueue((uint8_t*)buffer,len);
for (int i = 0; i < maxClients; i++)
{
gwClientPtr client = clients[i];
if (! client->hasClient()) continue;
if ( client->client->connected() ) {
bool rt=client->enqueue((uint8_t*)buffer,len);
if (!rt){
LOG_DEBUG(GwLog::DEBUG,"overflow in send to %s",(*it)->client->remoteIP().toString().c_str());
LOG_DEBUG(GwLog::DEBUG,"overflow in send to %s",client->remoteIp.c_str());
}
}
@ -167,5 +217,12 @@ void GwSocketServer::sendToClients(const char *buf){
}
int GwSocketServer::numClients(){
return clients.size();
int num=0;
for (int i = 0; i < maxClients; i++){
if (clients[i]->hasClient()) num++;
}
return num;
}
GwSocketServer::~GwSocketServer(){
}

View File

@ -2,7 +2,6 @@
#define _GWSOCKETSERVER_H
#include "GWConfig.h"
#include "GwLog.h"
#include <list>
#include <memory>
#include <WiFi.h>
@ -13,10 +12,12 @@ class GwSocketServer{
private:
const GwConfigHandler *config;
GwLog *logger;
std::list<gwClientPtr> clients;
gwClientPtr *clients;
WiFiServer *server=NULL;
int maxClients;
public:
GwSocketServer(const GwConfigHandler *config,GwLog *logger);
~GwSocketServer();
void begin();
void loop();
void sendToClients(const char *buf);