Рассмотрим следующее ПРИМЕР код:
#include <sys/socket.h>
int main()
{
int sv[ 2 ] = { 0 };
socketpair( AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, sv );
for( unsigned ii = 0; ii < 5; ++ii )
{
int* msg = new int( 123 );
if( -1 == send( sv[ 0 ], &msg, sizeof(int*), MSG_NOSIGNAL ) )
{
delete msg;
}
}
close( sv[0] );
sleep( 1 );
int* msg = 0;
int r;
while( ( r = read( sv[ 1 ], &msg, sizeof(int*) ) ) > 0 )
{
delete msg;
}
return 0;
}
Очевидно, что код работает нормально, но это не значит, что это не UB.
На страницах руководства ничего не нашлось, что гарантирует, что когда sv[ 0 ]
закрыт, read
все еще сможет прочитать все sv[ 1 ]
отправлено send
,
Может быть, вопрос можно задать так — как read
возвращается 0
за EOF
и как socketpair
является SOCK_STREAM
Я ожидаю EOF
будет «ударил», как только все будет прочитано из сокета и другая сторона будет закрыта. Это правильно?
AFAIK это может работать, но пахнет UB.
Правильный путь изящное отключение :
shutdown(s, 1)
или лучше shutdown(s, SHUT_WR)
)(Рекомендации : http://msdn.microsoft.com/en-us/library/windows/desktop/ms738547%28v=vs.85%29.aspx, Изящное завершение работы сокета в Linux)
Редактировать :
Прочитав комментарий R .., я подумал, не немного ли я запутался, провел несколько тестов и снова прочитал документацию. И … Теперь я думаю, что то, что я сказал, верно для общего использования сокетов (включая сокеты AF_INET), но не для специальной пары сокетов AF_INET.
Мой тест был немного перегружен системой, поскольку я отправлял 8 пакетов по 1024 байта в системе FreeBSD 9. Я остановился там, потому что отправка большего количества заблокировала бы. И после закрытия на sv [0] я смог успешно прочитать мои 8 пакетов.
Таким образом, он работает на разных ядрах, но не может найти для него действительную ссылку, за исключением того, что сокеты AF_UNIX не поддерживают данные OOB.
Я также мог бы подтвердить, что с помощью выключения работает нормально.
Заключение :
Что касается меня, я бы придерживался изящного отключения для закрытия сокета, но в основном потому, что я не хочу думать о базовом протоколе.
Надеюсь, что кто-то еще с большим знанием может дать часть справочной документации