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
WSASend
aufgerufen 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
WSAEWOULDBLOCK
bekommst wurde natürlich nichts verschickt, daher istbytes_sent == 0
nur natürlich. Wobei ich nicht weiss ob es garantiert ist dass der Wert inbytes_sent
Sinn macht wenn die Funktion einen Fehler gemeldet hat. Besser wärebytes_sent
im Fehlerfall gar nicht zu prüfen.IO auf einem non-blocking Socket kann jederzeit mit
WSAEWOULDBLOCK
fehlschlagen. 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
WSAEWOULDBLOCK
Fehler. Nur ignoriert dein Code wie schon gesagt explizitWSAEWOULDBLOCK
- und "re-interpretiert"WSAEWOULDBLOCK
dadurch 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_sent
dauerhaft = 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
-1
zurück undWSAGetLastError
liefertWSAEWOULDBLOCK
. Dein Code reagiert dann nur gleich darauf wie wennWSASend
erfolg 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_sent
ist nie 0, die Daten werden ggf. in mehreren Schleifendurchläufen komplett versendet.bytes_sent
ist 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_send
bleibt 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.