recv() вернёт пустой байт-массив только в одном случае - если другая сторона закрыла соединение на передачу данных (ну или в обе стороны).
Из твоего описания не очень понятно, ожидаешь ли ты закрытия соединения, или какого-то маркера конца сообщения, или вообще сообщения известной длины.
Также, что произойдёт, если передаваемые данные имеют длину ровно 4096 байт?
Если принимаешь данные до конца, то тогда можно упростить код приёма данных до чего-то вида
msg_parts = ""
while True:
part = conn.recv(4096)
if part:
msg_parts += part.decode() #по умолчанию это ascii.
#С многобайтными кодировками типа utf-8 могут быть проблемы,
#если многобайтный символ будет разбит границей пакета
while "\n" in msg_parts:
line, _, msg_parts = msg_parts.partition("\n")
yield line + "\n"
else:
break
yield msg_parts
Ну или в новом питоне можно еще короче
msg_parts = ""
while part := conn.recv(4096):
msg_parts += part.decode() #
while "\n" in msg_parts:
line, _, msg_parts = msg_parts.partition("\n")
yield line + "\n"
yield msg_parts