如何在Winsock2 C中停止/重新启动服务器套接字上的侦听和接受?

我在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.

相关文章

/** C+⬑ * 默认成员函数 原来C++类中,有6个默认成员函数: 构造函数 析构函数 拷贝...
#pragma once // 1. 设计一个不能被拷贝的类/* 解析:拷贝只会放生在两个场景中:拷贝构造函数以及赋值运...
C类型转换 C语言:显式和隐式类型转换 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译...
//异常的概念/*抛出异常后必须要捕获,否则终止程序(到最外层后会交给main管理,main的行为就是终止) try...
#pragma once /*Smart pointer 智能指针;灵巧指针 智能指针三大件//1.RAII//2.像指针一样使用//3.拷贝问...
目录&lt;future&gt;future模板类成员函数:promise类promise的使用例程:packaged_task模板类例程...