Implement RX buffer for WiFi client to speed up small reads

This commit is contained in:
me-no-dev 2018-07-05 22:31:58 +02:00
parent b0c6991bcf
commit 9efecc1be0
2 changed files with 127 additions and 17 deletions

View File

@ -31,6 +31,118 @@
#undef write #undef write
#undef read #undef read
class WiFiClientRxBuffer {
private:
size_t _size;
uint8_t *_buffer;
size_t _pos;
size_t _fill;
int _fd;
bool _failed;
size_t r_available()
{
if(_fd < 0){
return 0;
}
int count;
int res = lwip_ioctl_r(_fd, FIONREAD, &count);
if(res < 0) {
_failed = true;
return 0;
}
return count;
}
size_t fillBuffer()
{
if(!_buffer){
_buffer = (uint8_t *)malloc(_size);
}
if(_fill && _pos == _fill){
_fill = 0;
_pos = 0;
}
if(!_buffer || _size <= _fill || !r_available()) {
return 0;
}
int res = recv(_fd, _buffer + _fill, _size - _fill, MSG_DONTWAIT);
if(res < 0 && errno != EWOULDBLOCK) {
_failed = true;
return 0;
}
_fill += res;
return res;
}
public:
WiFiClientRxBuffer(int fd, size_t size=1436)
:_size(size)
,_buffer(NULL)
,_pos(0)
,_fill(0)
,_fd(fd)
,_failed(false)
{
//_buffer = (uint8_t *)malloc(_size);
}
~WiFiClientRxBuffer()
{
free(_buffer);
}
bool failed(){
return _failed;
}
int read(uint8_t * dst, size_t len){
if(!dst || !len || (_pos == _fill && !fillBuffer())){
return -1;
}
size_t a = _fill - _pos;
if(len <= a || ((len - a) <= (_size - _fill) && fillBuffer() >= (len - a))){
if(len == 1){
*dst = _buffer[_pos];
} else {
memcpy(dst, _buffer + _pos, len);
}
_pos += len;
return len;
}
size_t left = len;
size_t toRead = a;
uint8_t * buf = dst;
memcpy(buf, _buffer + _pos, toRead);
_pos += toRead;
left -= toRead;
buf += toRead;
while(left){
if(!fillBuffer()){
return len - left;
}
a = _fill - _pos;
toRead = (a > left)?left:a;
memcpy(buf, _buffer + _pos, toRead);
_pos += toRead;
left -= toRead;
buf += toRead;
}
return len;
}
int peek(){
if(_pos == _fill && !fillBuffer()){
return -1;
}
return _buffer[_pos];
}
size_t available(){
return _fill - _pos + r_available();
}
};
class WiFiClientSocketHandle { class WiFiClientSocketHandle {
private: private:
int sockfd; int sockfd;
@ -58,6 +170,7 @@ WiFiClient::WiFiClient():_connected(false),next(NULL)
WiFiClient::WiFiClient(int fd):_connected(true),next(NULL) WiFiClient::WiFiClient(int fd):_connected(true),next(NULL)
{ {
clientSocketHandle.reset(new WiFiClientSocketHandle(fd)); clientSocketHandle.reset(new WiFiClientSocketHandle(fd));
_rxBuffer.reset(new WiFiClientRxBuffer(fd));
} }
WiFiClient::~WiFiClient() WiFiClient::~WiFiClient()
@ -69,6 +182,7 @@ WiFiClient & WiFiClient::operator=(const WiFiClient &other)
{ {
stop(); stop();
clientSocketHandle = other.clientSocketHandle; clientSocketHandle = other.clientSocketHandle;
_rxBuffer = other._rxBuffer;
_connected = other._connected; _connected = other._connected;
return *this; return *this;
} }
@ -76,6 +190,7 @@ WiFiClient & WiFiClient::operator=(const WiFiClient &other)
void WiFiClient::stop() void WiFiClient::stop()
{ {
clientSocketHandle = NULL; clientSocketHandle = NULL;
_rxBuffer = NULL;
_connected = false; _connected = false;
} }
@ -100,6 +215,7 @@ int WiFiClient::connect(IPAddress ip, uint16_t port)
return 0; return 0;
} }
clientSocketHandle.reset(new WiFiClientSocketHandle(sockfd)); clientSocketHandle.reset(new WiFiClientSocketHandle(sockfd));
_rxBuffer.reset(new WiFiClientRxBuffer(sockfd));
_connected = true; _connected = true;
return 1; return 1;
} }
@ -260,11 +376,9 @@ size_t WiFiClient::write(Stream &stream)
int WiFiClient::read(uint8_t *buf, size_t size) int WiFiClient::read(uint8_t *buf, size_t size)
{ {
if(!available()) { int res = -1;
return -1; res = _rxBuffer->read(buf, size);
} if(_rxBuffer->failed()) {
int res = recv(fd(), buf, size, MSG_DONTWAIT);
if(res < 0 && errno != EWOULDBLOCK) {
log_e("%d", errno); log_e("%d", errno);
stop(); stop();
} }
@ -273,16 +387,12 @@ int WiFiClient::read(uint8_t *buf, size_t size)
int WiFiClient::peek() int WiFiClient::peek()
{ {
if(!available()) { int res = _rxBuffer->peek();
return -1; if(_rxBuffer->failed()) {
}
uint8_t data = 0;
int res = recv(fd(), &data, 1, MSG_PEEK);
if(res < 0 && errno != EWOULDBLOCK) {
log_e("%d", errno); log_e("%d", errno);
stop(); stop();
} }
return data; return res;
} }
int WiFiClient::available() int WiFiClient::available()
@ -290,14 +400,12 @@ int WiFiClient::available()
if(!_connected) { if(!_connected) {
return 0; return 0;
} }
int count; int res = _rxBuffer->available();
int res = lwip_ioctl_r(fd(), FIONREAD, &count); if(_rxBuffer->failed()) {
if(res < 0) {
log_e("%d", errno); log_e("%d", errno);
stop(); stop();
return 0;
} }
return count; return res;
} }
// Though flushing means to send all pending data, // Though flushing means to send all pending data,

View File

@ -28,11 +28,13 @@
#include <memory> #include <memory>
class WiFiClientSocketHandle; class WiFiClientSocketHandle;
class WiFiClientRxBuffer;
class WiFiClient : public Client class WiFiClient : public Client
{ {
protected: protected:
std::shared_ptr<WiFiClientSocketHandle> clientSocketHandle; std::shared_ptr<WiFiClientSocketHandle> clientSocketHandle;
std::shared_ptr<WiFiClientRxBuffer> _rxBuffer;
bool _connected; bool _connected;
public: public: