2017-06-01 1 views
0

Angenommen, die folgenden Code (der Einfachheit halber habe ich die notwendige Fehlerbehandlung hier weggelassen):Kann ich sicher sein, dass ein UDP recv sofort nach einem erfolgreichen Aufruf zum recv mit MSG_PEEK nicht blockiert wird?

recv(sockfd, NULL, 0, MSG_PEEK); 
recv(sockfd, buff, bufflen, 0); 

In diesem Fall: Kann ich sicher sein, dass nach dem ersten Aufruf zu recv das gesamte Datagramm bereits empfangen und daher wird der zweite Anruf an recv nicht blockieren?

Oder kann es passieren, dass, wenn IP das Datagramm aufteilt, die erste recv zurückgibt, sobald ein Teil dieses Datagramms empfangen wird, und die zweite recv wird blockiert, bis das gesamte Datagramm empfangen wird?

Wenn ich den ersten Anruf zu recv mit substituieren:

recv(sockfd, NULL, 0, MSG_PEEK | MSG_TRUNC); 

Kann ich sicher sein, dass dies nur einmal das gesamte Datagramm zurück empfangen wird, da sonst wäre es keine Möglichkeit für recv zuverlässig die zurück Länge des gesamten Datagramms, wie von MSG_TRUNC angefordert?

+1

Nicht, wenn es einen anderen Prozess oder Thread mit einer FD für den gleichen Socket gibt. Es könnte das Paket vor Ihnen lesen. – Barmar

Antwort

3

Kann ich sicher sein, dass nach dem ersten Aufruf das gesamte Datagramm an empf ist bereits erhalten und damit den zweiten Anruf wird nicht Block empf?

Ein UDP-Socket funktioniert in ganzen Datagramm-Einheiten. Der erste Aufruf wird erst zurückgegeben, wenn ein Datagramm verfügbar ist, es sei denn, es gibt -1 zurück, um auf einen Fehler hinzuweisen. (Ein TCP-Socket gibt möglicherweise 0 zurück, um das Schließen der Verbindung zu signalisieren, aber das wird bei einem UDP nicht passieren, da es verbindungslos ist.)

@Barmar beobachtet in Kommentaren, dass ein anderer Thread oder Prozess mit Zugriff auf die gleiche Socket könnte Prinzip, lies das wartende Datagramm vor demjenigen, der das erste recv() aufgerufen hat, aber wenn das kein Problem für dich ist, dann sollte das folgende recv() tatsächlich das ganze Datagramm zurückgeben, bis zu dem verfügbaren Platz im Puffer (irgendwelche überschüssigen Bytes in die Nachricht ist verloren). Natürlich wirft dies die Frage auf, warum Sie das tun wollen - Sie könnten genauso gut die erste recv() überspringen und die zweite blockieren lassen, falls nötig.

Das Hinzufügen von MSG_TRUNC zu den Flags ändert nichts davon. Auch hier arbeitet ein UDP-Socket in ganzen Datagramm-Einheiten. Der einzige Unterschied besteht darin, dass der Rückgabewert die Größe des Datagramms angibt. Das könnte ein Grund für den zusätzlichen Anruf recv() sein.

+0

Warum so ein Konstrukt? Ich habe zwei Threads, einen wiederholt nur 'recv' und den anderen wiederholt nur' send', nur um sie ihre Arbeit machen zu lassen, ohne warten zu müssen, bis der blockierende Socket-Aufruf des anderen zurückkommt. Der Einfachheit halber wollte ich den zweiten "recv" unter einem Mutex machen, der gemeinsame Daten sperrt, so dass dieser zweite "recv" in diese gemeinsamen Daten schreiben kann. Wenn diese zweite 'recv' nicht blockiert, ist es in Ordnung. Wenn es blockieren könnte, würde die ganze Idee keinen Sinn ergeben. – gaazkam