Как остановить / перезапустить прослушивание и принятие в сокете сервера в Winsock2 c++?

Я сделал сокет (Winsock2) в Visual Studio Pro c++ для прослушивания порта для соединений (TCP). Он работает отлично, но я позволяю ему работать в своем собственном потоке, и я хочу иметь возможность закрыть его с надеждой перезапустить его позже. Я могу завершить поток без проблем, но это не мешает сокету принимать новых клиентов (то есть он задерживается на принятии, которое он делал до того, как я закрыл поток). Я могу подключить к нему новых клиентов, но ничего не происходит... он просто принимает и это все. Я хочу, чтобы он перестал слушать и принимать, а затем смог сказать ему, чтобы он снова запустился позже в том же порту. Попытка перезапустить его сейчас просто говорит мне, что порт уже занят.

вот функция прослушивания потока:

DWORD WINAPI ListeningThread(void* parameter){
TCPServer *server = (TCPServer*)parameter;

try{
    server = new TCPServer(listen_port);
}catch(char* err){
    cout<<"ERROR: "<<err<<endl;
    return -1;
}

int result = server->start_listening();
if(result < 0){
    cout<<"ERROR: WSA Err # "<<WSAGetLastError()<<endl;
    return result;
}
cout<<"LISTENING: "<<result<<endl<<endl;
while(true){
    TCPClientProtocol *cl= new TCPClientProtocol(server->waitAndAccept());
    HANDLE clientThread = CreateThread(0, 0, AcceptThread, cl, 0, 0);
    cout<<"Connection spawned."<<endl;
}

return 0;
}

вот соответствующие функции в TCPServer:

TCPServer::TCPServer(int port){
listening = false;
is_bound = false;

//setup WSA
int result = WSAStartup(MAKEWORD(2, 2), (LPWSADATA) &wsaData);
if(result < 0){
    throw "WSAStartup ERROR.";
    return;
}

//create the socket
result = (serverSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP));
if(result < 0){
    throw "Socket Connect ERROR.";
    return;
}

//bind socket to address/port
SOCKADDR_IN sin;
sin.sin_family = PF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = INADDR_ANY;

result = bind(serverSocket, (LPSOCKADDR) &sin, sizeof(sin));
if(result < 0){
    throw "Could not Bind socket - Make sure your selected PORT is available.";
    return;
}

is_bound = true;
}

int TCPServer::start_listening(){
int result = -1;
if(is_bound){
    //SOMAXCONN parameter (max) is a backlog:
    //  how many connections can be queued at any time.
    result = listen(serverSocket, SOMAXCONN);
    if(result >= 0)
        listening = true;
}
return result;
}

SOCKET TCPServer::waitAndAccept(){
if(listening)
    return accept(serverSocket, NULL, NULL);
else
    return NULL;
}

Я пробовал оба closesocket () и shutdown (), но оба из них бросили ошибки.

спасибо всем за ваше время и помогите!

1 ответов


во-первых, убедитесь, что вы установили SO_REUSEADDR опция на сокете сервера, чтобы иметь возможность повторно начать прослушивание.

тогда, я предполагаю, ваша проблема в том, что accept() блоки и вы не можете остановить его, когда вам нужно, так вы убиваете нить. Плохое решение. Правильный ответ здесь-асинхронный ввод-вывод, т. е. select() или poll() или их аналоги Windows. Взгляните на Расширенные Образцы Winsock.

быстрое и грязное решение в многопоточном приложении-это проверьте некоторые is_it_time_to_stop_accepting_connections флаг перед каждым accept(), затем, когда пришло время остановиться, переверните флаг и подключитесь к порту прослушивания (да, в той же программе). Это разблокирует accept() и позволяют делать правильные closesocket() или что-то еще.

но серьезно, читайте на асинхронный ввод/вывод.