WSASend: lpNumberOfBytesSent gültiger Wert?
-
Hallo,
ich habe unter Windows einen non-blocking SOCKET, der iwie problematisch ist. Zum Versenden der Daten im Sendepuffer wird
WSASendaufgerufen und der lpNumberOfBytesSent Parameter mit der Anzahl der versendeten Byte befüllt.
Ist es ein zulässiger Anwendungsfall, dass lpNumberOfBytesSent 0 ist und beimWSASend-Aufruf nichts verschickt worden ist?
-
Hast du den Rückgabewert geprüft, wenn dieser Fall auftritt?
-
Ja, der wird geprüft. Ich weiß gar nicht, ob dieser Fall auftritt, aber die Sendefuntkion kann eigentlich nur in diesem Fall Probleme machen:
unsigned int TCPConnection::send() { if( !WriteBuffer_.empty() ) { WriteBuffer_.seek( 0, SeekOrigin::Begin ); while( WriteBuffer_.available() > 0 ) { int const pos = WriteBuffer_.tell(); int const count = WriteBuffer_.available(); char* data = WriteBuffer_.buffer() + pos; WSABUF buffer; buffer.buf = data; buffer.len = min( 1408, count ); DWORD bytes_sent = 0; if( ::WSASend( socket(), &buffer, 1, &bytes_sent, 0, nullptr, nullptr ) == SOCKET_ERROR ) { unsigned int const error_code = ::WSAGetLastError(); if( error_code != WSAEWOULDBLOCK ) { WriteBuffer_.erase_front(); return error_code; } } if( bytes_sent == 0 ) { ::PostMessage( SyncWindow_, TCPWindowMessages::SendData, socket(), 0 ); return 0; } WriteBuffer_.skip( bytes_sent ); connection_info().BytesSent += bytes_sent; connection_info().LastSendTime = timestamp_current_timestamp(); } WriteBuffer_.erase_front(); } return 0; }Die Zeilen 26-30 sind jetzt für den Fall ergänzt worden. Ansonsten würde der Datenzeiger im WriteBuffer im Falle von lpNumberOfBytesSent = 0 nicht verschoben und die while()-Schleife nicht verlassen.
-
sicher das in dem falle nicht WSAEWOULDBLOCK auftritt?
-
Nein, weiß ich nicht, daher die Frage. Ich dachte bisher, dass lpNumberOfBytesSent > 0 ist oder ein Fehler aufgetreten ist (return wert = SOCKET_ERROR). Ich möchte jetzt wissen, ob lpNumberOfBytesSent 0 sein darf, ohne dass ein Fehler aufgetreten ist. Also ob das Versenden von 0 Bytes als erfolgreich gilt, obwohl man 1+ Bytes versenden möchte.
-
@DocShoe sagte in WSASend: lpNumberOfBytesSent gültiger Wert?:
Nein, weiß ich nicht, daher die Frage. Ich dachte bisher, dass lpNumberOfBytesSent > 0 ist oder ein Fehler aufgetreten ist (return wert = SOCKET_ERROR). I
Dein Code ignoriert ja explizit
WSAEWOULDBLOCK:if( ::WSASend( socket(), &buffer, 1, &bytes_sent, 0, nullptr, nullptr ) == SOCKET_ERROR ) { unsigned int const error_code = ::WSAGetLastError(); if( error_code != WSAEWOULDBLOCK ) { WriteBuffer_.erase_front(); return error_code; } }Wenn du
WSAEWOULDBLOCKbekommst wurde natürlich nichts verschickt, daher istbytes_sent == 0nur natürlich. Wobei ich nicht weiss ob es garantiert ist dass der Wert inbytes_sentSinn macht wenn die Funktion einen Fehler gemeldet hat. Besser wärebytes_sentim Fehlerfall gar nicht zu prüfen.IO auf einem non-blocking Socket kann jederzeit mit
WSAEWOULDBLOCKfehlschlagen. Speziell kannst du dich nicht darauf verlassen dass du eine beliebige Menge an Daten verschicken kannst nachdem du perselect/... die Notification bekommen hast dass der socket jetzt "bereit zum Schreiben" ist.Ich möchte jetzt wissen, ob lpNumberOfBytesSent 0 sein darf, ohne dass ein Fehler aufgetreten ist. Also ob das Versenden von 0 Bytes als erfolgreich gilt, obwohl man 1+ Bytes versenden möchte.
Nein, das Versenden von 0 Bytes gilt nicht als erfolgreich. Statt dessen bekommst du in dem Fall einen
WSAEWOULDBLOCKFehler. Nur ignoriert dein Code wie schon gesagt explizitWSAEWOULDBLOCK- und "re-interpretiert"WSAEWOULDBLOCKdadurch als "erfolgreich".
-
Ah, danke. Ich bin jetzt auch davon ausgegangen, dass Erfolg bedeutet, dass min. 1 Byte verschickt worden ist.
Dann müssen wir unser Problem weiter untersuchen, wir haben die Vermutung, dass die while()-Schleife unter bestimmten Bedinungen nicht verlassen wird, und die einzige Erklärung ist, dass das nur mitbytes_sentdauerhaft = 0 auftreten kann.
-
Jetzt verstehe ich gar nichts mehr.
@DocShoe sagte in WSASend: lpNumberOfBytesSent gültiger Wert?:
Ich bin jetzt auch davon ausgegangen, dass Erfolg bedeutet, dass min. 1 Byte verschickt worden ist.
Tut es ja auch.
Wenn nichts gesendet werden kann weil die Buffer voll sind, dann bekommst du
-1zurück undWSAGetLastErrorliefertWSAEWOULDBLOCK. Dein Code reagiert dann nur gleich darauf wie wennWSASenderfolg gemeldet hätte.
-
@hustbaer sagte in WSASend: lpNumberOfBytesSent gültiger Wert?:
Jetzt verstehe ich gar nichts mehr.
Warum nicht, was ist unklar?
Mir ist jetzt jedenfalls klar geworden, warum der ursprüngliche Code ohne die Zeilen 26-30 fehlerhaft war:
Es gibt drei Fälle, die in einemsend- Aufruf auftreten können:bytes_sentist nie 0, die Daten werden ggf. in mehreren Schleifendurchläufen komplett versendet.bytes_sentist zwischenzeitlich mal 0, das spielt aber keine Rolle, weil in den nächsten Schleifendurchläufen der Rest der Daten versendet wird. Dieser Fall kann auftreten, wenn große Datenmengen versendet werden müssen und die Daten schneller zur Verfügung gestellt werden, als die Schnittstelle sie verschicken kann.bytes_sendbleibt dauerhaft 0, nur in diesem Fall wird diewhile-Schleife nie verlassen. Und das scheint unser Problemfall zu sein, daher habe ich die Zeilen 26-30 ergänzt. Warum dieser Fall auftritt müssen wir uns jetzt ansehen.