Probleme IOCP Queue bleibt hängen mit WRK Penetration Tool
-
Moin habe in meine Libnetplus das den Windows support hinzugefügt funktioniert auch leider nicht wenn ich mit dem wrk Tool um die 10000 Anfragen stelle dann friert die Queue ohne Meldung ein das Programm läuft weiter aber kann aber keine neuen Anfragen stellen:
Der Komplette Source code:
https://tuxist.de/git/jan.koester/libnetplusDas Project mit dem ich getestet (httpsysinfo) habe:
https://tuxist.de/git/jan.koester/libhttppp/-/tree/master/examples?ref_type=heads
Der Event Code:
/******************************************************************************* Copyright (c) 2014, Jan Koester jan.koester@gmx.net All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the <organization> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ #include <iostream> #include <algorithm> #include <chrono> #include <memory> #include <mutex> #include <cstring> #include <signal.h> #include <stdlib.h> #include <stdint.h> #include <winsock2.h> #include <ws2ipdef.h> #include <mswsock.h> #include <strsafe.h> #include <errno.h> #include "socket.h" #include "exception.h" #include "eventapi.h" #include "connection.h" #include <assert.h> #define READEVENT 0 #define SENDEVENT 1 #define BLOCKSIZE 16384 namespace netplus { enum IOState { IO_READ_STATE = 0, IO_WRITE_STATE = 1, IO_CLOSE_STATE = 2 }; class client { public: client(eventapi* eapi) : api(eapi), State(IO_READ_STATE), CurCon(nullptr) { api->CreateConnetion(&CurCon); } ~client() { if (CurCon) { api->deleteConnetion(CurCon); } } int State; eventapi* api; con* CurCon; mutable std::mutex cltmtx; }; class poll { public: poll(HANDLE iocp, eventapi* api, socket* ssock) : g_iocp(iocp), g_eventapi(api), g_serversocket(ssock) {} void AddToClientList(client* pClientContext) { std::lock_guard<std::mutex> lock(g_ClientContextMutex); g_ClientContext.push_back(pClientContext); } void AssociateWithIOCP(client* pClientContext) { //Associate the socket with IOCP HANDLE giocp2 = CreateIoCompletionPort((HANDLE)(pClientContext)->CurCon->csock->fd(), g_iocp, (ULONG_PTR)pClientContext, 0); if (!giocp2 || g_iocp != giocp2) { DWORD err = GetLastError(); NetException exp; exp[NetException::Error] << "AssociateWithIOCP fehlgeschlagen: Fehlercode " << err; throw exp; } } void RemoveFromClientList(client* pClientContext) { std::lock_guard<std::mutex> lock(g_ClientContextMutex); auto it = std::find(g_ClientContext.begin(), g_ClientContext.end(), pClientContext); if (it != g_ClientContext.end()) { g_ClientContext.erase(it); delete pClientContext; } } void AcceptConnection(LPFN_ACCEPTEX lpfnAcceptEx, int tid, ULONG_PTR args) { client* pClientContext = new client(g_eventapi); if (g_serversocket->_Type == TCP) pClientContext->CurCon->csock = new tcp(); try { g_serversocket->accept(lpfnAcceptEx, pClientContext->CurCon->csock); pClientContext->CurCon->csock->setNonBlock(); //Store this object AddToClientList(pClientContext); AssociateWithIOCP(pClientContext); } catch (NetException& e) { delete pClientContext->CurCon->csock; RemoveFromClientList(pClientContext); throw e; } g_eventapi->ConnectEvent(pClientContext->CurCon, tid, args); try { size_t recv = pClientContext->CurCon->csock->recvData(nullptr, 0, 0); WSAResetEvent(pClientContext->CurCon->csock->_Overlapped.hEvent); } catch (NetException& e) { std::cerr << e.what() << std::endl; if (e.getErrorType() != NetException::Note) throw e; } } private: HANDLE g_iocp; socket* g_serversocket; eventapi* g_eventapi; std::vector<client*> g_ClientContext; std::mutex g_ClientContextMutex; // NEU: mutex als Member friend class client; friend class EventWorker; }; void eventapi::RequestEvent(con* curcon, const int tid, ULONG_PTR args) { //dummy }; void eventapi::ResponseEvent(con* curcon, const int tid, ULONG_PTR args) { //dummy }; void eventapi::ConnectEvent(con* curcon, const int tid, ULONG_PTR args) { //dummy }; void eventapi::DisconnectEvent(con* curcon, const int tid, ULONG_PTR args) { //dummy }; void eventapi::CreateConnetion(con** curcon) { *curcon = new con(this); }; void eventapi::deleteConnetion(con* curcon) { delete curcon; }; event::event(socket* serversocket, int timeout) { if (!serversocket) { NetException exp; exp[NetException::Critical] << "server socket empty!"; throw exp; } _Timeout = timeout; _ServerSocket = serversocket; _ServerSocket->setNonBlock(); _ServerSocket->bind(); _ServerSocket->listen(); SYSTEM_INFO sysinfo; GetSystemInfo(&sysinfo); threads = sysinfo.dwNumberOfProcessors; } event::~event() { } class EventWorkerArgs { public: EventWorkerArgs() { } EventWorkerArgs(const EventWorkerArgs& eargs) { event = eargs.event; eviocp = eargs.eviocp; evpoll = eargs.evpoll; ssocket = eargs.ssocket; timeout = eargs.timeout; args = eargs.args; } int timeout; HANDLE eviocp; poll* evpoll; eventapi* event; socket* ssocket; void* args; }; class EventWorker { public: EventWorker(int tid, ULONG_PTR args, EventWorkerArgs* eargs) { for (;;) { ULONG_PTR lpContext = 0; OVERLAPPED* pOverlapped = nullptr; DWORD dwBytesTransfered = 0; bool bReturn = GetQueuedCompletionStatus( eargs->eviocp, &dwBytesTransfered, &lpContext, &pOverlapped, WSA_INFINITE); if (lpContext == 0) { continue; } client* pClientContext = (client*)lpContext; if (!bReturn && dwBytesTransfered == 0) { eargs->evpoll->RemoveFromClientList(pClientContext); continue; } try { auto& curCon = pClientContext->CurCon; switch (pClientContext->State) { case IO_WRITE_STATE: { std::lock_guard<std::mutex> lock(pClientContext->cltmtx); eargs->event->ResponseEvent(curCon, tid, args); ULONG ssize = curCon->SendData.size() < BLOCKSIZE ? (ULONG)curCon->SendData.size() : BLOCKSIZE; DWORD ret = 0; ret = curCon->csock->sendData(curCon->SendData.data(), ssize, 0); curCon->SendData.resize(ret); if (curCon->SendData.empty()) pClientContext->State = IO_READ_STATE; }break; case IO_READ_STATE: { std::lock_guard<std::mutex> lock(pClientContext->cltmtx); std::shared_ptr<char[]> buf(new char[BLOCKSIZE], std::default_delete<char[]>()); size_t recv = curCon->csock->recvData(buf.get(), BLOCKSIZE, 0); curCon->RecvData.append(buf.get(), recv); eargs->event->RequestEvent(curCon, tid, args); if (!curCon->SendData.empty()) pClientContext->State = IO_WRITE_STATE; }break; case IO_CLOSE_STATE: { WSACloseEvent(pClientContext->CurCon->csock->_Overlapped.hEvent); eargs->evpoll->RemoveFromClientList(pClientContext); }continue; } WSAResetEvent(pClientContext->CurCon->csock->_Overlapped.hEvent); } catch (NetException& e) { std::cerr << e.what() << std::endl; if (e.getErrorType() != NetException::Note) { pClientContext->State = IO_CLOSE_STATE; continue; } } catch (...) { std::cerr << "unknown error close coonection !" << std::endl; pClientContext->State = IO_CLOSE_STATE; continue; } } // for } }; void event::runEventloop(ULONG_PTR args) { NetException exception; EventWorkerArgs eargs; HANDLE iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 0); if (!iocp) { NetException exp; exp[NetException::Critical] << "event: runEventloop couldn't create iocp !"; throw exp; } LPFN_ACCEPTEX lpfnAcceptEx = NULL; GUID GuidAcceptEx = WSAID_ACCEPTEX; WSAOVERLAPPED olOverlap; DWORD dwBytes; memset(&olOverlap, 0, sizeof(olOverlap)); poll evpoll(iocp, this, _ServerSocket); eargs.ssocket = _ServerSocket; eargs.event = this; eargs.evpoll = &evpoll; eargs.timeout = _Timeout; eargs.eviocp = iocp; std::vector <std::thread> threadpool; for (int i = 0; i < threads; i++) { try { threadpool.push_back(std::thread([&eargs, args, i] { EventWorker(i, args, &eargs); })); } catch (NetException& e) { throw e; } } int iResult = WSAIoctl(_ServerSocket->fd(), SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidAcceptEx, sizeof(GuidAcceptEx), &lpfnAcceptEx, sizeof(lpfnAcceptEx), &dwBytes, NULL, NULL); if (iResult == SOCKET_ERROR) { NetException exp; exp[NetException::Critical] << "WSAIoctl failed with error: " << WSAGetLastError(); closesocket(_ServerSocket->fd()); WSACleanup(); throw exp; } WSAEVENT g_hAcceptEvent = WSACreateEvent(); WSANETWORKEVENTS WSAEvents; if (WSA_INVALID_EVENT == g_hAcceptEvent) { NetException exp; exp[NetException::Error] << "Error occurred while WSACreateEvent()."; throw exp; } if (SOCKET_ERROR == WSAEventSelect(_ServerSocket->fd(), g_hAcceptEvent, FD_ACCEPT | FD_READ | FD_WRITE)) { NetException exp; exp[NetException::Error] << "Error occurred while WSAEventSelect()."; WSACloseEvent(g_hAcceptEvent); throw exp; } for (;;) { if (WSA_WAIT_FAILED != WSAWaitForMultipleEvents(1, &g_hAcceptEvent, FALSE, WSA_INFINITE, FALSE)) { WSAEnumNetworkEvents(_ServerSocket->fd(), g_hAcceptEvent, &WSAEvents); if ((WSAEvents.lNetworkEvents & FD_ACCEPT) && (0 == WSAEvents.iErrorCode[FD_ACCEPT_BIT])) { try { evpoll.AcceptConnection(lpfnAcceptEx,0, args); } catch (NetException& e) { std::cerr << e.what() << std::endl; } } } } for (auto i = threadpool.begin(); i != threadpool.end(); ++i) { i->join(); } } };
-
@Tuxist1 sagte in Probleme IOCP Queue bleibt hängen mit WRK Penetration Tool:
Moin habe in meine Libnetplus das den Windows support hinzugefügt funktioniert auch leider nicht wenn ich mit dem wrk Tool um die 10000 Anfragen stelle dann friert die Queue ohne Meldung ein das Programm läuft weiter aber kann aber keine neuen Anfragen stellen:
Sorry, aber was willst du damit sagen? Ich verstehe da gerade gar nichts.
-
@Quiche-Lorraine wrk ist ein Benchmarktool für Httprequests bringt leider meine iocp layer ins straucheln so das er nicht mehr antwortet hatte schon Vermutung das was mit den Sockets zu tun hat.
-
geht jetzt werde noch bißchen weiter testen.
void RemoveFromClientList(client* pClientContext) { std::lock_guard<std::mutex> lock(g_ClientContextMutex); auto it = std::find(g_ClientContext.begin(), g_ClientContext.end(), pClientContext); if (it != g_ClientContext.end()) { if (pClientContext->cltmtx.try_lock()) { pClientContext->cltmtx.unlock(); g_ClientContext.erase(it); } } }
-
@Tuxist1 sagte in Probleme IOCP Queue bleibt hängen mit WRK Penetration Tool:
wrk ist ein Benchmarktool für Httprequests bringt leider meine iocp layer ins straucheln so das er nicht mehr antwortet hatte schon Vermutung das was mit den Sockets zu tun hat.
Sorry wenn ich das mal sage. Aber dein Schreibstil ist mir zu hektisch.
Ich vermute mal dass du einen Belastungstest durchgeführt hast und dadurch dein Code hängenbleibt.
Ein paar Punkte:
-
Dein komplettes Klassendesign gefällt mir nicht. Du nutzt sehr viele Pointer. Gerade in Sachen Threading ist dies nicht sinnvoll, da Verantwortlichkeiten nicht geklärt sind. Wer darf z.B. auf
client->api
zugreifen? Ist dieser Zugriff Thread Safe? Generell versuche ich für jeden Thread die Daten so lokal wie möglich zu halten. -
Warum nutzt du manuelle Speicherverwaltung? So etwas ist fehleranfällig und unnötig.
-
Achte bitte strikt auf Rückgabewerte. Folgender Code sieht strange aus:
bool bReturn = GetQueuedCompletionStatus( eargs->eviocp, &dwBytesTransfered, &lpContext, &pOverlapped, WSA_INFINITE); // Annahme bReturn ist false, dann darf die Funktion GetQueuedCompletionStatus // nach deinem Code pOverlapped nicht verändern. Kannst du das garantieren? if (lpContext == 0) { continue; } client* pClientContext = (client*)lpContext; if (!bReturn && dwBytesTransfered == 0) { // Gibt es auch den Zustand dass bReturn false ist, aber dwBytesTransfered > 0? eargs->evpoll->RemoveFromClientList(pClientContext); continue; }
- Ich würde dir auch empfehlen Logging zu nutzen. Beachte bitte aber dass Logging das Verhalten beeinflusst, da die Ausgabe ein paar Millisekunden fressen wird.
-
-
es wird noch ominöser haben jetzt auf anderen Rechner getestet mit Windows 11 Enterprise 24H2 der hat keine Probleme nur der mit Windows 11 IOT Enterprise 25H1 der schließt aus irgendeinem Grund keine Sockets habe ich durchs Logging heraus gefunden. Hat jemand eine Idee über die mögliche Ursache ?
-
ich glaube ich habe die Lösung der virtio win netzwerk treiber scheint fehlerhaft zu sein.
-
Finde es gut, dass du den ruppigen Beitrag von Quiche ignoriert hast
-
@Tuxist1 sagte in Probleme IOCP Queue bleibt hängen mit WRK Penetration Tool:
es wird noch ominöser haben jetzt auf anderen Rechner getestet mit Windows 11 Enterprise 24H2 der hat keine Probleme nur der mit Windows 11 IOT Enterprise 25H1 der schließt aus irgendeinem Grund keine Sockets habe ich durchs Logging heraus gefunden. Hat jemand eine Idee über die mögliche Ursache ?
Was sagt der Rückgabewert von
closesocket()
bzw.WSAGetLastError
?