Посмотрел тут недавно лайв кодинг одного прикольного чувака из Сибири, который стримит на Твиче и позже выкладывает на Ютубе.
Ниже ссылки на этот стрим на обоих ресурсах:
Этот стрим посвящён проблеме закрытия сокета до того, как все посланные данные на самом деле ушли к получателю. Суть проблемы в том, что функция write (как и неупомянутая в стриме send) пишет данные в ядро, а дошли ли эти данные до получателя уже полностью она не знает, хотя сокеты в Linux блокирующие по-умолчанию. Если сразу после write() или send() вызвать close(sock), у принимающей стороны случится ECONNRESET (Connection reset by peer). Случиться это может в случае, если и принимающая сторона решила что-то нам послать в самом начале, а мы это не прочитали. Это важное условие, потому что в противном случае всё работает верно и без ухищрений.
Первую половину ролика сибиряк разбирает одну старую статью на эту тему, пробует повторить и исправить по статье данную проблему в своём тестовом коде. Вторая половина ролика посвящена исправлению кода в его старых проектах и в контексте этой темы она не так интересна.
В статье предлагаются следующие шаги для решения данной проблемы:
Во-первых предлагается вызывать shutdown(sock, SHUT_WR) на отправляющей стороне сразу после последнего write. Но этого недостаточно, поэтому так же предлагается выставить опцию сокета SO_LINGER которая уже сама по себе должна решить проблему, но почему-то её не решает и это выглядит так, как будто она просто не работает. Есть и Linux-only вещи, такие как SIOCOUTQ ioctl(). Но универсальным решением предлагается просто бесконечный цикл, в котором вычитываются все данные и лишь затем можно закрывать сокет.
Я проверил на своём компьютере большинство из выше перечисленного и этот бесконечный цикл действительно работает, а SO_LINGER с и без shutdown(sock, SHUT_WR) и даже с shutdown(sock, SHUT_RDWR) действительно не работает. Но ведь решение с бесконечным чтением в цикле - это дыра уровня DDoS, ведь если ко мне будет идти бесконечный поток данных, сокет я никогда не закрою.
Ещё одно наблюдение. Если перед закрытием сокета вызвать shutdown(sock, SHUT_WR) и короткий sleep, это так же решает проблему. Неужели в UNIX/Linux/POSIX нет нормального решения данной проблемы?

