Linux, сокеты, неблокирующее соединение
Я хочу создать неблокирующее соединение.
Вот так:
socket.connect(); // returns immediately
Для этого я использую другой поток, бесконечный цикл и Linux epoll. Подобно этому (псевдокод):
// in another thread
{
create_non_block_socket();
connect();
epoll_create();
epoll_ctl(); // subscribe socket to all events
while (true)
{
epoll_wait(); // wait a small time(~100 ms)
check_socket(); // check on EPOLLOUT event
}
}
Если я запускаю сервер, а затем клиент, все это работает. Если я сначала запускаю клиент, подождите некоторое небольшое время, запустите сервер, а затем клиент не подключится.
Что я делаю неправильно? Может быть, это можно сделать по-другому?
Ответы
Ответ 1
Для асинхронного подключения вы должны использовать следующие шаги:
- создать сокет с
socket(..., SOCK_NONBLOCK, ...)
- начать соединение с
connect(fd, ...)
- если возвращаемое значение не равно
0
и EINPROGRESS
, а затем прервать с ошибкой
- ждать, пока
fd
не будет сигнализирован как готовый к выводу
- проверить состояние сокета с помощью
getsockopt(fd, SOL_SOCKET, SO_ERROR, ...)
- сделано
Нет циклов - если вы не хотите обрабатывать EINTR
.
Если клиент запускается первым, вы должны увидеть ошибку ECONNREFUSED
на последнем шаге. Если это произойдет, закройте сокет и начните с начала.
Трудно сказать, что не так с вашим кодом, не видя больше деталей. Я полагаю, что вы не прерываете ошибки в вашей операции check_socket
.
Ответ 2
Есть несколько способов проверить, успешно ли неблокирующее соединение.
- Сначала вызовите getpeername(), если произошел сбой с ошибкой ENOTCONN, соединение не удалось. затем вызовите getsockopt с SO_ERROR, чтобы получить ожидающую ошибку на сокете
- вызовите read длиной 0. Если чтение не удалось, соединение не удалось, и ошибка чтения указывает, почему не удалось установить соединение; чтение возвращает 0, если соединение успешно
- вызовите соединение снова; если errno EISCONN, соединение уже подключено, и первое соединение успешно.