C++ 修正了(可怕的错误)&引用;断言'px!=0';失败。”;在使用boost、std::map和多线程的聊天服务器中

C++ 修正了(可怕的错误)&引用;断言'px!=0';失败。”;在使用boost、std::map和多线程的聊天服务器中,c++,multithreading,boost,server,assertion,C++,Multithreading,Boost,Server,Assertion,我带着一个新问题回来了。我必须使用OOP制作一个新版本的同步聊天服务器。我将套接字存储在std::map中,其中键是客户端的名称,值是指向ip::tcp::socket的共享指针。自从我这样做以来,我一直遇到以下问题: 我启动服务器和几个客户端。他们成功地互相写信。但是,如果关闭其中一个连接,服务器将以这种方式中止: server: /sapmnt/HOME/i322722/usr/boost/include/boost/smart_ptr/shared_ptr.hpp:687: typena

我带着一个新问题回来了。我必须使用OOP制作一个新版本的同步聊天服务器。我将套接字存储在std::map中,其中键是客户端的名称,值是指向ip::tcp::socket的共享指针。自从我这样做以来,我一直遇到以下问题:

我启动服务器和几个客户端。他们成功地互相写信。但是,如果关闭其中一个连接,服务器将以这种方式中止:

server: /sapmnt/HOME/i322722/usr/boost/include/boost/smart_ptr/shared_ptr.hpp:687: 
typename boost::detail::sp_member_access<T>::type
boost::shared_ptr<T>::operator->() const [with T = 
boost::asio::basic_stream_socket<boost::asio::ip::tcp>; typename 
boost::detail::sp_member_access<T>::type = 
boost::asio::basic_stream_socket<boost::asio::ip::tcp>*]: Assertion `px != 0' failed.
问题并不是每次我关闭一个连接时都会发生(有时如果我想关闭第一个建立的连接,这没问题,但是下一个连接失败了),但大多数情况下我都会这样做。我想有好几次是在加入新客户时发生的,但我不是100%确定

我认为问题与std::map有关,更确切地说,与函数有关

Server::disconnectClient(...) 

在server.cpp中,但我不确定。在使用此结构之前,一切都很好,但是套接字和名称都有单独的std::列表,这很糟糕。我不知道问题到底出在哪里,也不知道如何解决。非常感谢您的帮助。

我真的很抱歉浪费了您的时间。今天我意识到发生了如此愚蠢的事情。第一个版本的程序只包含server.cpp和client.cpp(当然还有一个makefile)。在makefile中,我编译服务器和客户端,生成执行文件“server”和“client”。自从我切换到OOP版本以来,makefile生成的新执行文件一直是“serverMain”和“client”。然而,直到今天早上,我一直在调用“服务器”,所以一直是旧的非面向对象版本给出了奇怪的断言失败


我将把代码保存在这里,以防发生其他错误。非常感谢您的帮助。

听起来像是线程问题。您应该使用互斥锁保护
clientMap
上的操作。
clientMap[clientName]
将创建默认值(空)
shared\u ptr
,如果键不在映射中。。。您可以使用
clientMap.at(clientName)
来代替……这不是“简单、自包含”的意思。您的共享指针很可能在您上次使用它们之前过期(关闭将删除挂起的异步操作,这意味着不再有绑定保留引用,对象将被删除)。您可以接受自己的答案(因此Q i标记为已回答),并请从标题中删除“已修复”。在未来,考虑把问题缩小到更小的一点,你发布的每一行代码都减少了有人查看你的代码的可能性。祝你好运
#include<iostream>
#include<list>

#include<boost/thread.hpp>
#include<boost/bind.hpp>
#include<boost/asio.hpp>
#include<boost/asio/ip/tcp.hpp>
#include<boost/interprocess/smart_ptr/unique_ptr.hpp>

#include "common.h"
#include "server.h"

using namespace std;
using namespace boost::asio;
using namespace boost::asio::ip;

const string waitingMsg("Waiting for clients...\n");
const string totalClientsMsg("Total clients: ");
const int EOF_ERROR_CODE = 2;

map <string, socket_ptr> clientMap;

Server::Server(io_service& serv) : service(serv), acceptor(service, ip::tcp::endpoint(ip::tcp::v4(), PORT_NO))
{
}

void Server::start()
{
    cout << waitingMsg;
    while (true)
    {
        socket_ptr sock(new tcp::socket(service));

        boost::system::error_code error;
        acceptor.accept(*sock, error);
        if (error)
        {
            cerr << "Error on accepting: " << error.message() << endl;
            cout << waitingMsg;
            continue;
        }

        boost::shared_ptr <boost::thread> p (new boost::thread(boost::bind(&Server::identify, this, sock)));
    }
}

void Server::writeMessage(const string& clientName, string& message)
{
    mtx.lock();
    boost::system::error_code error;
    message.append(1, '\n');
    for(auto& cliSock : clientMap)
    {
        if (cliSock.second->is_open() && cliSock.first != clientName)
        {
            cliSock.second->write_some(buffer(message), error);
            if (error)
            {
                cerr << errorWritingMsg << error.message() << endl;
            }
        }
    }
    mtx.unlock();
}

void Server::notification(const string& clientName, const string headOfMsg, const string tailOfMsg)
{
    string serviceMsg = headOfMsg + clientName + tailOfMsg;
    cout << serviceMsg << totalClientsMsg << clientMap.size() << endl;

    writeMessage(clientName, serviceMsg);

    cout << waitingMsg;
}

void Server::disconnectClient(const string& clientName)
{
    mtx.lock();

    boost::system::error_code error;
    clientMap[clientName]->shutdown(tcp::socket::shutdown_both, error);
    if (error)
    {
        cerr << "Error on shutting: " << error.message() << endl;
    }
    clientMap[clientName]->close(error);
    if(error)
    {
        cerr << "Error on closing: " << error.message() << endl;
    }

    clientMap.erase(clientName);
    mtx.unlock();

    notification(clientName, "", " disconnected. ");
}

bool Server::readMessage(socket_ptr sock, string& message)
{
    mtx.lock();
    boost::asio::streambuf buff;
    boost::system::error_code error;
    size_t bytes_transferred = boost::asio::read_until(*sock, buff, '\n', error);
    if(error)
    {
        if (error.value() != EOF_ERROR_CODE)
        {
            cerr << errorReadingMsg << error.message() << endl;
        }
        return false;
    }

    buff.commit(bytes_transferred);
    istream istrm(&buff);

    getline(istrm, message);
    mtx.unlock();
    if(message + "\n" == "exit\n")
    {
        return false;
    }
    return true;
}

void Server::processLoop(const string& clientName)
{
    while (true)
    {
        {
            string message = "";
            if (!readMessage(clientMap[clientName], message))
            {
                disconnectClient(clientName);
                return;
            }

            message.insert(0, clientName + ": ");

            writeMessage(clientName, message);
        }
    }
}

void Server::identify(socket_ptr sock)
{
    mtx.lock();
    sock->write_some(buffer("Please, enter your name:\n"));
    mtx.unlock();

    string name = "";

    boost::system::error_code error;
    bool occupied;

    do
    {
        if (!readMessage(sock, name))
        {
            return;
        }

        occupied = false;

        if (clientMap.find(name) != clientMap.end())
        {
            occupied = true;
        }

        if (occupied)
        {
            mtx.lock();
            sock->write_some(buffer("This name is already in use! Please, enter another name:\n"), error);
            mtx.unlock();

            if (error)
            {
                cerr << errorWritingMsg << error.message() << endl;
            }
        }
    }
    while (occupied);

    mtx.lock();
    clientMap.emplace(name, sock);
    mtx.unlock();

    notification(name, "New client: ", " joined. ");
    processLoop(name);
}
#include<iostream>

#include<boost/thread.hpp>
#include<boost/bind.hpp>
#include<boost/asio.hpp>
#include<boost/asio/ip/tcp.hpp>
#include<boost/algorithm/string.hpp>

#include "common.h"

using namespace std;
using namespace boost::asio;
using namespace boost::asio::ip;

io_service service;
tcp::endpoint ep(ip::address::from_string(IP), PORT_NO);

void displayLoop(socket_ptr sock)
{
    while(true)
    {
        {
            boost::asio::streambuf buff;

            boost::system::error_code error;
            size_t bytes_transferred = boost::asio::read_until(*sock, buff, '\n', error);
            if (error)
            {
                cerr << errorReadingMsg << error.message() << endl;
                continue;
            }

            buff.commit(bytes_transferred);
            istream istrm(&buff);
            string message = "";
            getline(istrm, message);
            buff.consume(buff.size());

            cout << message << endl;
        }
    }
}

void writeLoop(socket_ptr sock)
{
    string message = "";

    while(true)
    {
        getline(cin, message);

            message += '\n';

            boost::system::error_code error;
            sock->write_some(buffer(message), error);

            if (error)
            {
                cerr << errorWritingMsg << error.message() << endl;
                continue;
            }

            if(message == "exit\n")
            {
                exit(0);
            }

        message.clear();
    }
}


int main(int argc, char* argv[])
{
    boost::thread_group threads;
    socket_ptr sock(new tcp::socket(service));
    boost::system::error_code error;
    sock->connect(ep, error);
    if (error)
    {
        cerr << "Error on connecting: " << error.message() << endl;
        return -1;
    }

    cout << "Type \"exit\" to quit.\n";

    threads.create_thread(boost::bind(displayLoop, sock));
    threads.create_thread(boost::bind(writeLoop, sock));

    threads.join_all();

    return 0;
}
#ifndef COMMON_H_INCLUDED__ 
#define COMMON_H_INCLUDED__

#include<string>

typedef boost::shared_ptr<boost::asio::ip::tcp::socket> socket_ptr;

const unsigned PORT_NO = 30001;
const std::string IP = "127.0.0.1";

const std::string errorWritingMsg("Error on writing: ");
const std::string errorReadingMsg("Error on reading: ");

const std::string exitLower = "exit\n";
const std::string exitCapInit = "Exit\n";
const std::string exitCaps = "EXIT\n";

#endif
#include<boost/asio.hpp>

#include "common.h"
#include "server.h"

using namespace std;
using namespace boost::asio;
using namespace boost::asio::ip;

int main(int argc, char *argv[])
{
    boost::asio::io_service service;
    Server server(service);

    server.start();
    return 0;
}
all: serverMain client

libraries = -lboost_thread -lboost_system 

server.o: server.cpp
    g++ -I/sapmnt/HOME/i322722/usr/boost/include/ $(libraries) -L/sapmnt/HOME/i322722/usr/boost/lib/ -c server.cpp -std=c++11 -lrt -ggdb

serverMain.o: serverMain.cpp
    g++ -I/sapmnt/HOME/i322722/usr/boost/include/ $(libraries) -L/sapmnt/HOME/i322722/usr/boost/lib/ -c serverMain.cpp -std=c++11 -lrt -ggdb

client.o: client.cpp
    g++ -I/sapmnt/HOME/i322722/usr/boost/include/ $(libraries) -L/sapmnt/HOME/i322722/usr/boost/lib/ -c client.cpp -std=c++11 -lrt

server.o: server.cpp
    g++ -c server.cpp -lpthread $(libraries) -L/sapmnt/HOME/i322722/usr/boost/lib -std=c++11 -lrt -ggdb

serverMain: serverMain.o server.o
    g++ -o serverMain serverMain.o server.o -lpthread $(libraries) -L/sapmnt/HOME/i322722/usr/boost/lib -std=c++11 -lrt -ggdb

client: client.o
    g++ -o client client.o -lpthread $(libraries) -L/sapmnt/HOME/i322722/usr/boost/lib -std=c++11 -lrt

clean:
    rm *.o serverMain client
Server::disconnectClient(...)