2015-02-18 9 views
5

У меня есть клиентское приложение, которое взаимодействует с процессом QEMU через сокет домена QMP Unix. Иногда после того, как клиент вызывает close() в соединении сокетов, «netstat -ap unix» все еще показывает его в состоянии CONNECTED. Я проверяю возвращаемое значение вызова close(), и оно возвращается успешно со значением 0, но соединение все еще кажется затяжным.Домен домена UNIX не закрыт после закрытия()

Поскольку QMP на самом деле не поддерживает несколько подключений в своем сокете, все последующие вызовы для подключения к сокету терпят неудачу, так как они ждут неопределенно долгое время для закрытия закрывающего соединения.

Есть ли способ убедиться в том, что код действительно закрыт, и есть ли способ заставить сокет закрыть?

+1

Похоже, что серверный процесс QEMU не полностью прочитал содержимое последней отправки(). Что произойдет, если вы переключитесь на использование TCP вместо сокетов домена? Есть ли разница в поведении? – user590028

+0

Поведение, которое я только что описал, не воспроизводится на 100%, и, к сожалению, использование TCP не является для меня вариантом. – mgamal

+0

Можем ли мы видеть вывод 'netstat -ap'? – user590028

ответ

-1

Вы можете просто попробовать SO_LINGER через опцию setsockopt (2) с таймаутом 0. Таким образом, когда вы закрываете сокет, принудительно закрывается, отправляя RST вместо перехода в режим закрытия FIN/ACK.

Назначение опции SO_LINGER заключается в управлении отключением сокета при вызове функции close (2). Этот параметр применяется только к протоколам, ориентированным на соединение, таким как TCP.

Поведение ядра по умолчанию заключается в том, чтобы позволить функции close (2) немедленно вернуться к вызывающему. Любые неотправленные данные TCP/IP будут передаваться и поставляться, если это возможно, но никаких гарантий не предусмотрено. Поскольку вызов close (2) немедленно возвращает управление вызывающему абоненту, приложение не знает, действительно ли был доставлен последний бит данных.

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

Один заключительный сценарий может быть применен с использованием различных значений опции SO_LINGER. Если вызывающее приложение хочет немедленно прекратить связь, соответствующие значения могут быть установлены в структуре задержки. Затем вызов для закрытия (2) инициирует прерывание линии связи, отбрасывание всех ожидающих данных и немедленное закрытие сокета.

+0

. Он не гарантирует, что оба конца подтвердили нормальное завершение работы. Это только убеждает вызывающего, что все ожидающие данные были отправлены. – EJP

+0

Соответствующий сокет - это файловый UNIX-сокет, поэтому я не уверен, что здесь следует использовать SO_LINGER. – mgamal

0

Вы пытались закрыть розетку с другого конца? Он асинхронный, но дает обеим сторонам возможность обеспечить закрытие гнезда.

Вы можете отправить команду закрытия до слушателя на другом конце и перезагрузить ее. Когда розетка закрывается, вы должны получить SIGPIPE. Поймайте SIGPIPE и закройте конец гнезда. Если вы закончите с EPIPE, то проигнорируйте его. Это означает, что вы уже были уведомлены о закрытии сокета.

+0

QEMU уже делает это. – mgamal

1

Может быть, дескриптор файла был dup ed, fork ed, или просочился.

Звоните shutdown(sock, SHUT_RDWR) на это, чтобы закрыть соединение наверняка перед close ing.

+0

Попробуй это. Спасибо – mgamal

+0

Я использовал для получения -EAGAIN всякий раз, когда пытался подключиться к новому сокету, если другое соединение задерживается. После того, как я использовал shutdown(), я мог фактически подключиться() к сокету без получения -EAGAIN, даже если другой сокет не близок() d – mgamal