How to stop / restart listening and receiving on a server socket in Winsock2 C ++?

I made a socket (Winsock2) in Visual Studio Pro C ++ to listen on the port for connections (TCP). It works fine, but I let it work in its thread, and I want to be able to close it with the hope of restarting it later. I can end the stream without problems, but this does not prevent the socket from accepting new clients (that is, it lingers on the receptions that it did before I closed the stream). I can connect new clients to it, but nothing happens ... it just accepts and does it. I want him not to listen and not accept, and then he could say that he will start again later on the same port. Trying to restart it now just tells me that the port is already done.

Here is the stream listen function:

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; } 

Here are the related functions in 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; } 

I tried both closesocket () and shutdown (), but both of them threw errors.

Thank you all for your time and help!

+8
source share
2 answers

First, make sure that you set the SO_REUSEADDR parameter on the server socket to restart listening.

Then, I assume your problem is that the blocks are accept() and you cannot stop it when you need it, so you kill the thread. Bad decision. The correct answer here is asynchronous I / O, i.e. select() or poll() or their Windows counterparts. See Winsock Advanced Examples .

A quick and dirty solution in a multi-threaded application is to check the is_it_time_to_stop_accepting_connections flag before each accept() , and then when it stops, flip the flag and connect to the listening port (yes, in the same program). This unlocks accept() and allows you to make the correct closesocket() or something else.

But seriously, read asynchronous I / O.

+9
source

"A quick and dirty solution in a multi-threaded application is to check some is_it_time_to_stop_accepting_connections flag before each accept (), then when it is time to stop, flip the flag and connect to the listening port (yes, in the same program). Unlocks accept () and allows you to do the correct closesocket () or something else. "

While I came up with myself, my search for other tricks led me to this post ... I really appreciate your answer. Simple, elegant and everything works! It also allowed me to do aperiodic internal connections to free up the acceptance block and ensure that it will still be viable for slow periods of connection / dropout activity. Thanks again!

0
source

All Articles