我在Visual Studio Pro C中创建了一个套接字(Winsock2)来监听端口上的连接(TCP).它工作得很好,但我让它在自己的线程中运行,我希望能够关闭它,希望以后重新启动它.我可以毫无问题地终止线程,但这样做并不会阻止套接字接受新客户端(也就是说,它在我关闭线程之前就已经接受了它所做的接受).我可以将新客户连接到它但没有任何反应……它只是接受而且就是这样.我想要的是阻止它听取和接受,然后能够告诉它稍后在同一个端口再次启动.现在尝试重新启动它只是告诉我端口已经被占用.
这是listen线程函数:
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,AcceptThread,cl,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(),但这两个都引发了错误.
谢谢大家的时间和帮助!
解决方法
首先,确保在服务器套接字上设置SO_REUSEADDR选项才能重新开始侦听.
然后,我猜,你的问题是accept()块,你不能在需要时停止它,所以你杀了线程.解决方案不好这里正确的答案是异步I / O,即select()或poll()或它们的Windows对应物.看看Advanced Winsock Samples.
多线程应用程序中的快速解决方案是在每个accept()之前检查一些is_it_time_to_stop_accepting_connections标志,然后在停止时,翻转标志并连接到侦听端口(是的,在同一程序中).这将取消阻塞accept()并允许你做适当的closesocket()或其他.
但严重的是,请阅读asynchronous I/O.