客户端断开连接后,服务器应用程序崩溃

时间:2015-09-21 18:57:35

标签: c++ multithreading sockets winsock

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

以下是其工作原理的快速摘要:

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

std::vector <Client*> clients;
while (true){
    clients.push_back(&Client(accept(serverSocket, NULL, NULL), this));
}

当新客户端连接到服务器时,我们基本上使用新客户端的套接字和服务器本身作为参数创建一个新的Client对象。

我的想法是给每个客户端提供自己的线程,这样每个客户端都可以同时发送数据。

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

如果客户端断开连接,则告诉服务器从连接的客户端向量中删除客户端,然后设置&#34; isConnected&#34; 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;
}

所以是的,我真的不知道造成这次崩溃的原因,但是我怀疑它可能与使用客户端功能的线程有关,因为它正在被删除客户端矢量的服务器。

如果事实证明这是问题,你们可以给我一些想法,以便更好地实现每个拥有自己线程的客户吗?

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

2 个答案:

答案 0 :(得分:4)

错误出现在这段代码中:

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删除vectorstd::vector<std::unique_ptr<Client>> clients; while (true){ clients.push_back(std::make_unique<Client>(accept(serverSocket, NULL, NULL), this)); } 本身时自动释放它们。然后你的代码变成:

{{1}}

答案 1 :(得分:3)

在这段代码中:

clients.push_back(&Client(accept(serverSocket, NULL, NULL), this));

您正在将临时对象的地址推送到容器中。当push_back()完成时,临时对象将被销毁,因此该地址不再有效。我想知道,什么样的编译器允许你这样做。