boost asio第二课 多线程异步服务器历程一个错误的例子

简介:

namespace AppCom
{

class CAppComSession : public boost::enable_shared_from_this<CAppComSession>
{
public:
    CAppComSession(boost::asio::io_service &io_service) : m_socket(io_service)
    {
        m_bRunning = true;
    }
    ~CAppComSession()
    {

// m_thread->join();
// m_socket.close();
}

    void Start()
    {
        static boost::asio::ip::tcp::no_delay option(true);
        m_socket.set_option(option);
        m_thread.reset(new boost::thread(boost::bind(&CAppComSession::StartThread, this)));
        m_thread->detach();
    }

    void StartThread()
    {
        do 
        {
            boost::system::error_code ec;
            char szRecvBuf[10240] = { 0 };
            int nReadLen = m_socket.read_some(boost::asio::buffer(szRecvBuf), ec);
            if (ec)
            {
                LOG4CPLUS_ERROR(LOGGERTAG, "come across boost asio read error:" << ec);
                break;
            }
            LOG4CPLUS_INFO(LOGGERTAG, "recv app message:" << szRecvBuf);
            std::string strResponse;

            int nRet = ProcessAPPMsg(szRecvBuf, strResponse);
            if (0 != nRet) break;

            int nLen = boost::asio::write(m_socket, boost::asio::buffer(strResponse, strResponse.length()), ec);
            LOG4CPLUS_INFO(LOGGERTAG, "send app response message:" << strResponse);
        } while (0);
        m_bRunning = false;
        //m_socket.close();
    }

    boost::asio::ip::tcp::socket &GetSocket()
    {
        return m_socket;
    }

    bool GetCurThreadRunningStatus()
    {
        return m_bRunning;
    }

private:
    boost::asio::ip::tcp::socket m_socket;
    bool m_bRunning;
    boost::shared_ptr<boost::thread> m_thread;
};

typedef boost::shared_ptr<CAppComSession> CPtrSession;

class CAppComServer
{
public:

    CAppComServer(boost::asio::io_service &io_service, boost::asio::ip::tcp::endpoint &endpoint)
        :m_ioService(io_service), m_acceptor(io_service, endpoint)
    {
        CPtrSession newSession(new CAppComSession(io_service));
        m_vecThreadInstance.push_back(newSession);
        m_acceptor.async_accept(newSession->GetSocket(),
            boost::bind(&CAppComServer::HandleAccept,
                this,
                newSession,
                boost::asio::placeholders::error));
    }

    void HandleAccept(CPtrSession newSession, const boost::system::error_code &error)
    {
        if (error)  return;

        newSession->Start();
        //ClearHasEndConnection();
        CPtrSession createNewSession(new CAppComSession(m_ioService));
        //m_vecThreadInstance.push_back(createNewSession);
        m_acceptor.async_accept(createNewSession->GetSocket(),
            boost::bind(&CAppComServer::HandleAccept,
                this,
                createNewSession,
                boost::asio::placeholders::error));
    }

    void ClearHasEndConnection()
    {
        std::vector<CPtrSession>::iterator iter;
        iter = m_vecThreadInstance.begin();
        while (iter != m_vecThreadInstance.end())
        {
            if (!(*iter)->GetCurThreadRunningStatus())
            {
                iter->reset();
                m_vecThreadInstance.erase(iter);
                break;
            }
            iter++;
        }
    }

    void run()
    {
        m_ioService.run();
    }

private:
    boost::asio::io_service &m_ioService;
    std::vector<CPtrSession> m_vecThreadInstance;
    boost::asio::ip::tcp::acceptor m_acceptor;
};

void ListenAppComFunc();

int StartAppComService();

}

说明
这里跟之前的asio 异步服务器是有很大的区别
1)套接字可以不用关闭,其次也不需要担心线程的返回问题
2)不再需要保存请求处理的实例,自然也就没有管理所有实例的必要性,至于什么时候退出,服务器的接收线程不需要考虑

错误提醒:
在实际的应用环境中,在读数据m_socket.read_some(boost::asio::buffer(szRecvBuf), ec)的时候,会产生套接字错误,返回10035,代表含义是在一个非套接字上尝试了一个操作。 
出现原因分析:
当线程分离的时候,accept函数开始等待下一个请求,createNewSession由于是智能指针,跳出了函数,开始调用析构函数进行对象的清理,这个时候m_socket已经被清理掉了,很多类的成员变量已经无法被使用了,m_vecThreadInstance.push_back(createNewSession);却能够保存对象的实例,不至于马上调用析构函数,如果调用该函数的话,就必须自己定时清理已经服务完毕的对象



     本文转自fengyuzaitu 51CTO博客,原文链接:http://blog.51cto.com/fengyuzaitu/2044782,如需转载请自行联系原作者




相关文章
|
1月前
|
编解码 数据安全/隐私保护 计算机视觉
Opencv学习笔记(十):同步和异步(多线程)操作打开海康摄像头
如何使用OpenCV进行同步和异步操作来打开海康摄像头,并提供了相关的代码示例。
78 1
Opencv学习笔记(十):同步和异步(多线程)操作打开海康摄像头
|
2月前
|
安全 Java 调度
Java编程时多线程操作单核服务器可以不加锁吗?
Java编程时多线程操作单核服务器可以不加锁吗?
44 2
|
1月前
|
网络协议 Unix Linux
一个.NET开源、快速、低延迟的异步套接字服务器和客户端库
一个.NET开源、快速、低延迟的异步套接字服务器和客户端库
|
1月前
|
安全 调度 C#
STA模型、同步上下文和多线程、异步调度
【10月更文挑战第19天】本文介绍了 STA 模型、同步上下文和多线程、异步调度的概念及其优缺点。STA 模型适用于单线程环境,确保资源访问的顺序性;同步上下文和多线程提高了程序的并发性和响应性,但增加了复杂性;异步调度提升了程序的响应性和资源利用率,但也带来了编程复杂性和错误处理的挑战。选择合适的模型需根据具体应用场景和需求进行权衡。
|
1月前
|
网络协议 安全 Java
难懂,误点!将多线程技术应用于Python的异步事件循环
难懂,误点!将多线程技术应用于Python的异步事件循环
61 0
|
2月前
|
设计模式 缓存 Java
谷粒商城笔记+踩坑(14)——异步和线程池
初始化线程的4种方式、线程池详解、异步编排 CompletableFuture
谷粒商城笔记+踩坑(14)——异步和线程池
|
3月前
|
缓存 Java
异步&线程池 线程池的七大参数 初始化线程的4种方式 【上篇】
这篇文章详细介绍了Java中线程的四种初始化方式,包括继承Thread类、实现Runnable接口、实现Callable接口与FutureTask结合使用,以及使用线程池。同时,还深入探讨了线程池的七大参数及其作用,解释了线程池的运行流程,并列举了四种常见的线程池类型。最后,阐述了在开发中使用线程池的原因,如降低资源消耗、提高响应速度和增强线程的可管理性。
异步&线程池 线程池的七大参数 初始化线程的4种方式 【上篇】
|
3月前
|
Java 数据库
异步&线程池 CompletableFuture 异步编排 实战应用 【终结篇】
这篇文章通过一个电商商品详情页的实战案例,展示了如何使用`CompletableFuture`进行异步编排,以解决在不同数据库表中查询商品信息的问题,并提供了详细的代码实现和遇到问题(如图片未显示)的解决方案。
异步&线程池 CompletableFuture 异步编排 实战应用 【终结篇】
|
3月前
|
Java
Java使用FileInputStream&&FileOutputStream模拟客户端向服务器端上传文件(单线程)
Java使用FileInputStream&&FileOutputStream模拟客户端向服务器端上传文件(单线程)
83 1
|
3月前
|
Java
异步&线程池 CompletableFuture 异步编排 【下篇】
这篇文章深入探讨了Java中的`CompletableFuture`类,解释了如何创建异步操作、使用计算完成时的回调方法、异常处理、串行化方法、任务组合以及多任务组合的使用方式,并通过代码示例展示了各种场景下的应用。
异步&线程池 CompletableFuture 异步编排 【下篇】