一旦客户端断开连接,服务器应用程序就会崩溃
Server application crashing as soon as a client disconnects
所以我刚刚使用 winsock2 和 TCP 编写了一个简单的多线程客户端服务器应用程序。
以下是其工作原理的简要总结:
服务器主线程处于无限循环中接受客户端,然后将它们添加到服务器向量中,该向量包含每个连接的客户端,如下所示:
(只为我的问题添加重要内容)
std::vector <Client*> clients;
while (true){
clients.push_back(&Client(accept(serverSocket, NULL, NULL), this));
}
当一个新的客户端连接到服务器时,我们基本上会创建一个新的客户端对象,并将新客户端的套接字和服务器本身作为参数。
当时我的想法是给每个客户端一个线程,这样每个客户端都可以同时发送数据。
std::thread tickThread;
Client::Client(SOCKET socket,Server* server) :
isConnected(true),
socket(socket),
server(server)
{
tickThread = std::thread(&Client::tick,this);
}
客户端的线程然后检查客户端是否发送了一些东西,然后将它发送到服务器。它还检查客户端是否仍然连接。
void Client::tick(){
while (isConnected){
errorHandler = recv(socket, receivedData, 255, 0);
if (errorHandler == SOCKET_ERROR){
disconnect();
}
else {
//send received data to server
}
}
如果客户端断开连接,它会告诉服务器从已连接的客户端矢量中删除客户端,然后将 "isConnected" 布尔值设置为 false,以便线程可以退出其功能。
void Client::disconnect(){
isConnected = false;
server->removeClient(this);
}
这是它应该如何工作的,但是一旦客户端再次断开连接,服务器就会崩溃并出现错误:
R6010 - 已调用 abort()
所有调试都显示这是我的错误:
switch (_CrtDbgReportW(_CRT_ERROR, NULL, 0, NULL, L"%s", error_text)){
case 1: _CrtDbgBreak(); msgshown = 1; break;
case 0: msgshown = 1; break;
}
所以是的,我真的不知道是什么导致了这次崩溃,但是我怀疑它可能与使用客户端函数的线程有关,该函数基本上被删除了,因为它正在从服务器。
如果事实证明这是问题所在,你们能给我一些想法,让我更好地实现每个客户端都有自己的线程吗?
编辑:更改了向量错误,但是一旦客户端断开连接,崩溃仍然会发生
在这段代码中:
clients.push_back(&Client(accept(serverSocket, NULL, NULL), this));
您正在将临时对象的地址推送到容器中。 push_back() 完成后,临时对象被销毁,因此该地址不再有效。我想知道,什么样的编译器允许你这样做。
错误在这段代码中:
while (true){
clients.push_back(&Client(accept(serverSocket, NULL, NULL), this));
}
Client(accept(serverSocket, NULL, NULL), this)
是一个表达式,它生成一个临时 Client
对象,该对象在语句完成执行时被销毁。但是,您获取该临时对象的地址并将其添加到您的 vector
.
如果要创建 Client
对象并存储指向它们的指针,则需要为它们分配内存。我建议使用 std::unique_ptr
来管理它们,以便您的 vector
声明对它们内存的所有权,并在它们从 vector
中删除或 vector
本身被破坏时自动释放它们.然后你的代码变成:
std::vector<std::unique_ptr<Client>> clients;
while (true){
clients.push_back(std::make_unique<Client>(accept(serverSocket, NULL, NULL), this));
}
所以我刚刚使用 winsock2 和 TCP 编写了一个简单的多线程客户端服务器应用程序。
以下是其工作原理的简要总结:
服务器主线程处于无限循环中接受客户端,然后将它们添加到服务器向量中,该向量包含每个连接的客户端,如下所示: (只为我的问题添加重要内容)
std::vector <Client*> clients;
while (true){
clients.push_back(&Client(accept(serverSocket, NULL, NULL), this));
}
当一个新的客户端连接到服务器时,我们基本上会创建一个新的客户端对象,并将新客户端的套接字和服务器本身作为参数。
当时我的想法是给每个客户端一个线程,这样每个客户端都可以同时发送数据。
std::thread tickThread;
Client::Client(SOCKET socket,Server* server) :
isConnected(true),
socket(socket),
server(server)
{
tickThread = std::thread(&Client::tick,this);
}
客户端的线程然后检查客户端是否发送了一些东西,然后将它发送到服务器。它还检查客户端是否仍然连接。 void Client::tick(){
while (isConnected){
errorHandler = recv(socket, receivedData, 255, 0);
if (errorHandler == SOCKET_ERROR){
disconnect();
}
else {
//send received data to server
}
}
如果客户端断开连接,它会告诉服务器从已连接的客户端矢量中删除客户端,然后将 "isConnected" 布尔值设置为 false,以便线程可以退出其功能。
void Client::disconnect(){
isConnected = false;
server->removeClient(this);
}
这是它应该如何工作的,但是一旦客户端再次断开连接,服务器就会崩溃并出现错误:
R6010 - 已调用 abort()
所有调试都显示这是我的错误:
switch (_CrtDbgReportW(_CRT_ERROR, NULL, 0, NULL, L"%s", error_text)){
case 1: _CrtDbgBreak(); msgshown = 1; break;
case 0: msgshown = 1; break;
}
所以是的,我真的不知道是什么导致了这次崩溃,但是我怀疑它可能与使用客户端函数的线程有关,该函数基本上被删除了,因为它正在从服务器。
如果事实证明这是问题所在,你们能给我一些想法,让我更好地实现每个客户端都有自己的线程吗?
编辑:更改了向量错误,但是一旦客户端断开连接,崩溃仍然会发生
在这段代码中:
clients.push_back(&Client(accept(serverSocket, NULL, NULL), this));
您正在将临时对象的地址推送到容器中。 push_back() 完成后,临时对象被销毁,因此该地址不再有效。我想知道,什么样的编译器允许你这样做。
错误在这段代码中:
while (true){
clients.push_back(&Client(accept(serverSocket, NULL, NULL), this));
}
Client(accept(serverSocket, NULL, NULL), this)
是一个表达式,它生成一个临时 Client
对象,该对象在语句完成执行时被销毁。但是,您获取该临时对象的地址并将其添加到您的 vector
.
如果要创建 Client
对象并存储指向它们的指针,则需要为它们分配内存。我建议使用 std::unique_ptr
来管理它们,以便您的 vector
声明对它们内存的所有权,并在它们从 vector
中删除或 vector
本身被破坏时自动释放它们.然后你的代码变成:
std::vector<std::unique_ptr<Client>> clients;
while (true){
clients.push_back(std::make_unique<Client>(accept(serverSocket, NULL, NULL), this));
}