c++ - 一旦客户端断开连接,服务器应用程序就会崩溃

标签 c++ multithreading sockets winsock

所以我只是使用 winsock2 和 TCP 编写了一个简单的多线程客户端服务器应用程序。

以下是其工作原理的简要总结:

服务器主线程处于无限循环中接受客户端,然后将它们添加到服务器 vector 中,该 vector 包含每个连接的客户端,如下所示: (只为我的问题添加重要的内容)

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

如果客户端断开连接,它会告诉服务器从已连接的客户端 vector 中删除客户端,然后将“isConnected” bool 值设置为 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;
}

所以是的,我真的不知道是什么导致了这次崩溃,但我怀疑它可能与使用客户端功能的线程有关,该线程基本上被删除,因为它正在从服务器的客户端 vector 中删除。

如果这确实是问题所在,你们能给我一些想法,让我更好地实现每个客户端都有自己的线程吗?

编辑:更改了 vector 错误,但是一旦客户端断开连接,崩溃仍然会发生

最佳答案

错误在这段代码中:

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

关于c++ - 一旦客户端断开连接,服务器应用程序就会崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32702647/

相关文章:

c++ - 终止 pthreads

c# - C# += 线程安全吗?

遍历目录时的 C 编程段错误

c++ - 如何使用两个发送函数发送 GET 请求?

c++ - 定义扩展为文字的宏 #

c++ - 可变参数模板的 N 元笛卡尔积

c++ - C++将对象强制转换为其原始类型

c++ - 调用虚拟方法的不同方式

node.js - 如何最好地使用socket.io和pub/sub创建与API调用的连接-Node.js

sockets - 什么是消息边界?