Безопасно ли считывать данные из трубы ИЛИ сокет-пары с закрытым концом до достижения EOF?

Рассмотрим следующее ПРИМЕР код:

#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 будет «ударил», как только все будет прочитано из сокета и другая сторона будет закрыта. Это правильно?

0

Решение

AFAIK это может работать, но пахнет UB.

Правильный путь изящное отключение :

  • shutdown(s, 1) или лучше shutdown(s, SHUT_WR))
  • читать до eof на входе
  • только тогда позвони близким.

(Рекомендации : 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.

Я также мог бы подтвердить, что с помощью выключения работает нормально.

Заключение :
Что касается меня, я бы придерживался изящного отключения для закрытия сокета, но в основном потому, что я не хочу думать о базовом протоколе.

Надеюсь, что кто-то еще с большим знанием может дать часть справочной документации

0

Другие решения


По вопросам рекламы [email protected]