A
Der komfortabelste Weg, auf Fehler zu reagieren, sind Exceptions: sie räumen den Stack auf und können gefangen werden, wenn es sich anbietet. Wie der Name sagt, sind Exceptions aber für den Ausnahmefall gedacht, etwa, wenn ein wilder Zeiger dereferenziert wird, wenn ein gewöhnliches Programm nicht genug Speicher bekommen kann, wenn einer Funkion unzulässige Parameter übergeben werden, kurz, immer, wenn mit dem Fehler eigentlich nicht gerechnet wird.
Für alltäglichere Fehler mag es dennoch sinnvoll sein, einen Rückgabewert auszuwerten, u.a., da hierdurch kein Exception-Overhead entsteht. So ist das ja in den Funktionen des Windows-API geregelt.
Prinzipiell wertet Fehler nur aus, wer vernünftig darauf reagieren kann. Wenn ein Anwender deiner Socket-Klasse auf einen entsprechenden Fehler im Programmcode reagieren will, fängt er die Exception, ansonsten eben nicht. Auf der UI-Ebene sollte dann noch ein try-catch-Block sein, der alle Exceptions fängt, eine Fehlermeldung an den Benutzer ausgibt und, wenn es notwendig sein sollte, das Programm terminiert.