Я обнаружил странную ошибку с TCP-сокетами.Похоже, что SO_KEEPALIVE
включено во всех сокетах по умолчанию.
Я написал короткий тестовый пример для создания сокета и подключения к серверу.Сразу после подключения я проверяю SO_KEEPALIVE
с getsockopt
.Значение отличное от нуля, что в соответствии с MSDN означает, что поддержка активности включена.Может быть, я неправильно понимаю это.
Недавно у меня была странная ошибка, когда сервер отключался дважды подряд.Некоторые клиенты находились в состоянии, когда они отправили информацию для входа и ожидали ответа.Несмотря на то, что в сокете, подключенном к серверу, было размещено перекрывающееся WSARecv
, сообщение о том, что сервер вышел из строя, не было отправлено, поэтому я предполагаю, что сокет не был полностью закрыт.
Примерно через 2 часа (фактически около 1 часа, 59 минут и 19 секунд) для чтения был отправлен пакет завершения, уведомляющий клиента о том, что соединение больше не открыто.Именно здесь я начал подозревать SO_KEEPALIVE
.
Я пытаюсь понять, почему это произошло.Это вызвало небольшую проблему, потому что клиенты, которые по какой-либо причине теряют соединение, должны автоматически подключаться к серверу;в этом случае, поскольку об отключении не было сообщено, клиент не переподключался до 2 часов спустя.
Очевидным решением является установка тайм-аута, но я хотел бы знать, как эта ситуация может возникнуть.
SO_KEEPALIVE
не установлен на сокете моим сервером приложений или клиентом.
// Error checking is removed for this snippet, but all winsock calls succeed.
int main() {
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
SOCKET foo = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0);
DWORD optval;
int optlen = sizeof(optval);
int test = 0;
test = getsockopt(foo, SOL_SOCKET, SO_KEEPALIVE, (char*)&optval, &optlen);
std::cout << "Returned " << optval << std::endl;
sockaddr_in clientService;
clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr("127.0.0.1");
clientService.sin_port = htons(446);
connect(foo, (SOCKADDR*) &clientService, sizeof(clientService));
test = getsockopt(foo, SOL_SOCKET, SO_KEEPALIVE, (char*)&optval, &optlen);
std::cout << "Returned " << optval << std::endl;
std::cin.get();
return 0;
}
// Example output:
// Returned 2883584
// Returned 2883584