Программа на другом конце сокета не закрывает ее и не закрывает свои записи (которые являются вашими чтениями), поэтому ваш конец не знает, что все закончено - действительно, логически оно не закончено, пока другой конец не скажет, что вам больше нечего читать.
Как правило, вашей логике прикладного уровня необходимо заранее знать, сколько читать или читать, пока не получен определенный терминатор, или другой конец грациозно закрывает или закрывает сокет.
(Неблокирующий ввод-вывод - это нечто совершенно другое - он позволяет вам делать другие вещи, эффективно считывая данные из сокетов в одном потоке, но это не решает проблему определения того, когда вы закончили чтение из сокет, который является вашей проблемой.)