У меня есть серверная программа, которая подключается к другой программе через данный сокет, и в некоторых случаях мне нужно закрыть соединение и почти сразу же снова открыть его в том же сокете. По большому счету это работает, за исключением того, что мне нужно ждать ровно одну минуту, пока сокет не перезагрузится Тем временем netstat указывает, что сервер видит сокет в FIN_WAIT2, а клиент видит его как CLOSE_WAIT. Я уже использую SO_REUSEADDR, который, как я думал, предотвратит ожидание, но это не помогает. Установка SO_LINGER в ноль также не помогает. Что еще я могу сделать, чтобы решить эту проблему?
Вот соответствующие фрагменты кода:
SetUpSocket()
{
// Set up the socket and listen for a connection from the exelerate client.
// Open a TCP/IP socket.
m_baseSock = socket(PF_INET, SOCK_STREAM, IPPROTO_IP);
if (m_baseSock < 0)
{
return XERROR;
}
// Set the socket options to reuse local addresses.
int flag = 1;
if (setsockopt(m_baseSock, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) == -1)
{
return XERROR;
}
// Set the socket options to prevent lingering after closing the socket.
//~ linger li = {1,0};
//~ if (setsockopt(m_baseSock, SOL_SOCKET, SO_LINGER, &li, sizeof(li)) == -1)
//~ {
//~ return XERROR;
//~ }
// Bind the socket to the address of the current host and our given port.
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(m_port);
if (bind(m_baseSock, (struct sockaddr*)&addr, sizeof(addr)) != 0)
{
return XERROR;
}
// Tell the socket to listen for a connection from client.
if (listen(m_baseSock, 4) != 0)
{
return XERROR;
}
return XSUCCESS;
}
ConnectSocket()
{
// Add the socket to a file descriptor set.
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(m_baseSock, &readfds);
// Set timeout to ten seconds. Plenty of time.
struct timeval timeout;
timeout.tv_sec = 10;
timeout.tv_usec = 0;
// Check to see if the socket is ready for reading.
int numReady = select(m_baseSock + 1, &readfds, NULL, NULL, &timeout);
if (numReady > 0)
{
int flags = fcntl(m_baseSock, F_GETFL, 0);
fcntl(m_baseSock, flags | O_NONBLOCK, 1);
// Wait for a connection attempt from the client. Do not block - we shouldn't
// need to since we just selected.
m_connectedSock = accept(m_baseSock, NULL, NULL);
if (m_connectedSock > 0)
{
m_failedSend = false;
m_logout = false;
// Spawn a thread to accept commands from client.
CreateThread(&m_controlThread, ControlThread, (void *)&m_connectedSock);
return XSUCCESS;
}
}
return XERROR;
}
ControlThread(void *arg)
{
// Get the socket from the argument.
socket sock = *((socket*)arg);
while (true)
{
// Add the socket to a file descriptor set.
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(sock, &readfds);
// Set timeout to ten seconds. Plenty of time.
struct timeval timeout;
timeout.tv_sec = 10;
timeout.tv_usec = 0;
// Check if there is any readable data on the socket.
int num_ready = select(sock + 1, &readfds, NULL, NULL, &timeout);
if (num_ready < 0)
{
return NULL;
}
// If there is data, read it.
else if (num_ready > 0)
{
// Check the read buffer.
xuint8 buf[128];
ssize_t size_read = recv(sock, buf, sizeof(buf));
if (size_read > 0)
{
// Get the message out of the buffer.
char msg = *buf;
if (msg == CONNECTED)
{
// Do some things...
}
// If we get the log-out message, log out.
else if (msg == LOGOUT)
{
return NULL;
}
}
}
} // while
return NULL;
}
~Server()
{
// Close the sockets.
if (m_baseSock != SOCKET_ERROR)
{
close(m_baseSock);
m_baseSock = SOCKET_ERROR;
}
if (m_connectedSock != SOCKET_ERROR)
{
close(m_connectedSock);
m_connectedSock = SOCKET_ERROR;
}
}
SOCKET_ERROR равно -1. Объект сервера уничтожается, после чего соединение должно закрываться, а затем повторно создаваться, и в этот момент вызываются подпрограммы SetUpSocket () и ConnectSocket ().
Так почему я должен подождать минуту, пока сокет не очистится? Любые идеи будут оценены.
EDIT:
Следуя советам моих первых авторов, я нашел способ заставить клиента закрыть сокет с его конца. Что-то все еще не правильно, хотя. Теперь netstat показывает сокет с точки зрения сервера в TIME_WAIT, а запись с точки зрения клиента отсутствует. Все, что у меня есть, это:
tcp 0 0 localhost.localdomain: 19876 localhost.localdomain: 54598 TIME_WAIT
и ничего с другой стороны. Серверу и клиенту все еще требуется ровно минута для очистки TIME_WAIT, чтобы иметь возможность восстановить соединение. Теперь, что не так - использование close () в сокете клиента некорректно?
РЕДАКТИРОВАТЬ 2:
Теперь, если я заставлю клиента переподключиться, это произойдет немедленно - но если я просто позволю ему сделать свое дело, он будет ждать целую минуту, пока TIME_WAIT очистится. Я подозреваю, что что-то не так в коде клиента Не слишком много я могу с этим поделать.