websocket 在C++类中封装异步Web服务器和异步Web套接字

ulmd4ohb  于 2023-03-18  发布在  其他
关注(0)|答案(2)|浏览(209)

我正在努力将一个web服务器和一个WebSocket服务器封装到一个c++类中。
这是我想打包到类中的结构

SemaphoreHandle_t smphr;

AsyncWebServer webserver(80);
AsyncWebSocket websocket("/ws");

void onWsEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len) {
  if (xSemaphoreTake(smphr, 50) == pdTRUE) {
    if (type == WS_EVT_DATA) {
      Serial.print("Event Data received\n");
    }
    xSemaphoreGive(smphr);
  }
}

void setupWebserver() {
  webserver.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
    request->send_P(200, "text/html", index_html);
  });
  websocket.onEvent(onWsEvent);
  webserver.addHandler(&websocket);
}

这里websocket.onEvent(onWsEvent);行是正确的,没有任何编译错误
下面是我在类中封装服务器的尝试:

// webservice.h
class WebService {
public:
    explicit WebService();
    virtual ~WebService();

    static WebService* getInstance() { return s_instance; } 

    void setup();
    void onWsEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len);

private:
    static WebService* s_instance;

    SemaphoreHandle_t _smphr;

    AsyncWebServer *webserver = new AsyncWebServer(80);
    AsyncWebSocket *websocket = new AsyncWebSocket("/ws");
};

// webservice.cpp
WebService* WebService::s_instance = nullptr;

WebService::WebService()
{
    s_instance = this;
    _smphr = xSemaphoreCreateBinary();
    xSemaphoreGive(_smphr);  // release semaphores for first use
}

WebService::~WebService() {
  vSemaphoreDelete(_smphr);
  delete webserver;
  delete websocket;
}

void WebService::onWsEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len) {
  if (xSemaphoreTake(_smphr, 50) == pdTRUE) {
    if (type == WS_EVT_DATA) {
      Serial.print("Event Data received\n");
    }
    xSemaphoreGive(_smphr);
  }
}

void WebService::setup() {
  webserver->on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
    request->send_P(200, "text/html", index_html);
  });
  websocket->onEvent(onWsEvent); //error: invalid use of non-static member function
  webserver->addHandler(websocket);
}

**问题:**谁能告诉我我必须做什么,以摆脱编译错误“无效使用非静态成员函数”?
编辑

编译输出:

Compiling .pio/build/esp32-poe/libd4b/webService/webService.cpp.o
lib/webService/webService.cpp: In member function 'void WebService::setup()':
lib/webService/webService.cpp:172:33: error: invalid use of non-static member function
   m_websocket->onEvent(onWsEvent);
                                 ^
*** [.pio/build/esp32-poe/libd4b/webService/webService.cpp.o] Error 1
vsnjm48y

vsnjm48y1#

就像@kiner_shah在注解中建议的那样,我必须要么使onWsEvent()函数成为静态的,要么把它移到类之外。使它成为静态的不起作用,因为我使用了信号量,所以我必须把函数移到类之外。

SemaphoreHandle_t smphr;

void onWsEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len) {
  if (xSemaphoreTake(smphr, 50) == pdTRUE) {
    if (type == WS_EVT_DATA) {
      Serial.print("Event Data received\n");
    }
    xSemaphoreGive(smphr);
  }
}

void WebService::setup() {

  smphr = xSemaphoreCreateBinary();
  xSemaphoreGive(smphr);  // release semaphores for first use

  webserver->on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
    request->send_P(200, "text/html", index_html);
  });
  websocket->onEvent(onWsEvent);
  webserver->addHandler(websocket);
}

它现在可以工作了,但是我不太喜欢这个解决方案(我不能访问onWsEvent中的类变量和函数)。我必须承认我不明白为什么onWsEvent必须在类之外。也许它和这里提到的“自由函数”有关:https://devblogs.microsoft.com/oldnewthing/20140127-00/?p=1963
我还查找了AsyncWebserver的源代码,以查看onEvent是否被声明为static,但没有找到任何证据:

typedef std::function<void(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len)> AwsEventHandler;

//WebServer Handler implementation that plays the role of a socket server
class AsyncWebSocket: public AsyncWebHandler {

  private:
    ...
    AwsEventHandler _eventHandler;
    ...
  public:
    //event listener
    void onEvent(AwsEventHandler handler){
      _eventHandler = handler;
    }
xjreopfe

xjreopfe2#

在chatgpt的一点帮助下,我终于用我想要的方式解决了它!
问题在于使用非静态成员函数作为onEvent事件的回调函数。由于非静态成员函数需要一个隐式this指针,该指针指向调用它们的对象,因此它们不能用作常规函数。
解决这个问题的一个方法是使用静态成员函数或lambda函数作为回调函数,并将类的this示例作为用户参数传递给回调函数。这样,您就可以访问类示例及其成员。

// webservice.h
class WebService {
public:
    explicit WebService();
    virtual ~WebService();

    static WebService* getInstance() { return s_instance; } 

    void setup();
    // below is new:
    static void staticWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len, void *thisweb) {
        WebService *self = reinterpret_cast<WebService *>(thisweb);
        self->onWsEvent(server, client, type, arg, data, len);
    }
    // end new
    void onWsEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len);

private:
    static WebService* s_instance;

    SemaphoreHandle_t _smphr;

    AsyncWebServer *webserver = new AsyncWebServer(80);
    AsyncWebSocket *websocket = new AsyncWebSocket("/ws");
};

// webservice.cpp
WebService* WebService::s_instance = nullptr;

WebService::WebService()
{
    s_instance = this;
    _smphr = xSemaphoreCreateBinary();
    xSemaphoreGive(_smphr);  // release semaphores for first use
}

WebService::~WebService() {
  vSemaphoreDelete(_smphr);
  delete webserver;
  delete websocket;
}

void WebService::onWsEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len) {
  if (xSemaphoreTake(_smphr, 50) == pdTRUE) {
    if (type == WS_EVT_DATA) {
      Serial.print("Event Data received\n");
    }
    xSemaphoreGive(_smphr);
  }
}

void WebService::setup() {
  webserver->on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
    request->send_P(200, "text/html", index_html);
  });
  m_websocket->onEvent([this](AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {
    WebService::staticWsEvent(server, client, type, arg, data, len, this);
  }); // now works!!
  webserver->addHandler(websocket);
}

相关问题