关闭客户端连接的两种情况

关于连接状态改变的情况
客户端下线的两种方式
1.客户端主动下线
子线程会收到socket状态改变的消息
/* 连接状态改变 */
static void conn_eventcb(struct bufferevent *bev, short events, void *user_data)
{
    auto c2 = (Channel2*)user_data;
    auto c = c2->channel;
    if(c->m_is_disconnected)
    {
        int a = 0;
        return ;
    }
    static int offline = 0;
    if((events & BEV_EVENT_EOF) || (events & BEV_EVENT_ERROR))
    {
        { //如果已经下线,即不用做下线处理
            std::lock_guard<std::mutex> lock(c2->ser->m_lts_mtx);
            if(!c2->ser->m_allChannels[c->m_id])
                return;
        }
        //printf("Connection closed.\n"); //BEV_EVENT_EOF
        printf("Got an error on the connection: %s channel_id = %d, offline = %d, wait_offline = %d\n",
            strerror(errno), c->m_id, ++offline, c2->ser->m_offline_que.size());/*XXX win32*/
        {
            c->m_is_disconnected = true;
            c->m_event->on_stat_change(c->m_id, link_stat::link_disconnected);
        }
        {
            auto ser = c2->ser;
            LibEvtServer::OffChannel2 offc2 = { GetTickCount(), bev->ev_read.ev_fd, c2};

            {//防止libevent thread 和 主线程(send_data)同时访问m_offline_que。
                std::lock_guard<std::mutex> lock(ser->m_offline_mtx);
                ser->m_offline_que.push(offc2);
#ifdef MUL_LIBEVENT_THREAD
            }
            {//防止多个libevent thread 线程同时访问下面公共变量
                std::lock_guard<std::mutex> lock(ser->m_lts_mtx);
#endif
                ser->m_allChannels[c->m_id] = NULL;
                ser->m_ids->freeId(c->m_id);//[L]将id归还。
            }
            //int read_fd = bev->ev_read.ev_fd;
            //int write_fd = bev->ev_write.ev_fd;
        }

    }
    /* None of the other events can happen here, since we haven‘t enabled
     * timeouts */
}

2.踢下线
bool LibEvtServer::close_channel(int channel_id)
{
    auto c2 = m_allChannels[channel_id];
    if(!c2->channel || c2->channel->m_is_disconnected)
        return false;

    auto c = c2->channel;
    LibEvtServer::OffChannel2 offc2 = { GetTickCount(), c->m_bev->ev_read.ev_fd, c2};
    {
        std::lock_guard<std::mutex> lock(m_offline_mtx);
        m_offline_que.push(offc2);//他也是将其push到这个下线队列中
#ifdef MUL_LIBEVENT_THREAD
    }
    {//防止多个libevent thread 线程同时访问下面公共变量
        std::lock_guard<std::mutex> lock(m_lts_mtx);
#endif
        m_allChannels[c->m_id] = NULL;
        m_ids->freeId(c->m_id);//[L]将id归还。
    }
    return true;
}

在主线程中是什么时候关闭套接字的呢
在包发送超过100个的时候执行一次下线
bool LibEvtServer::free_one_link()
{
    /**
     *①让主线程来决定连接,为了保证bufferevent_write的第一个参数绝对有效;
     *②一次处理一个,保证实时性。
     */
    if(m_offline_que.size())
    {
        OffChannel2* offc2 = NULL;
        {
            std::lock_guard<std::mutex> lock(m_offline_mtx);
            offc2 = &(m_offline_que.front());//注意需要用成员的引用或地址
        }
        if(offc2->c2)
        {
            delete offc2->c2->channel;//bufferevent_free(...)
            delete offc2->c2;
            offc2->c2 = nullptr;
        }
        if((GetTickCount() - offc2->offtime) > 60*1000)//延时60秒关闭套接字,保证工作线程调完套接字操作
        {
            evutil_closesocket(offc2->sockfd);    //跨平台关闭套接字函数:Linux - close(fd); Windows - closesocket(fd)
            std::lock_guard<std::mutex> lock(m_offline_mtx);
            m_offline_que.pop();
        }
    }

    return false;
}
注意这个写直接是主线程在写,读是在线程,释放连接也是在主线程,在线程释放连接时会延迟60s,防止子线程对socket进行读操作,
这就造成了踢下线客户端不能及时收到通知,得1min之后才能提示下线,关键这种延迟关闭个人感觉也不是太好,让主线程成取写,然后主线程取关闭套接字这样为什么就能保证操作的套接字无效,我也不太清楚
时间: 2024-10-08 23:44:16

关闭客户端连接的两种情况的相关文章

用sql取出来的list需要处理成map的两种情况

1. 原生sql: select a.id,a.name from a SQLQuery sqlQuery=this.getSession().createSQLQuery(sb.toString()); List list = sqlQuery.list(); 在action处理成map: 2.hql: select new map(a.id as id,a.name as name) from a this.getHibernateTemplate().find(sb.toString())

Nginx访问PHP文件的File not found错误处理,两种情况

Nginx访问PHP文件的File not found错误处理,两种情况 这个错误很常见,原有有下面两种几种 1. php-fpm找不到SCRIPT_FILENAME里执行的php文件 2. php-fpm不能访问所执行的php,也就是权限问题 第一种情况 可以在你的location php 里面添加当文件不存在时返回404而不是交给php-fpm进行处理 location ~ \.php${ ... #文件不存在转404 try_files $uri = 404; ...} 然后,在你的配置文

在两种情况下设备与驱动会发生匹配

在两种情况下设备与驱动会发生匹配:(基于linux内核3.0) 当设备插入系统时,设备挂接到总线上,与总线上的所有驱动进行匹配(bus_type.match进行匹配), 如果匹配成功,则调用bus_type.probe或者driver.probe初始化该设备,挂接到总线上,如果匹配失败,则只是将该设备挂接到总线上. 当驱动注册到系统时,驱动挂接到总线上,与总线上的所有设备进行匹配(用bus_type.match进行匹配),如果匹配成功,则调用bus_type.probe或者driver.prob

java项目打jar包的两种情况

链接地址:http://jingyan.baidu.com/article/6b97984d8a6ddc1ca2b0bfa0.html 本文介绍一下java项目打jar包时的两种情况各怎么操作 方法/步骤 一.java项目没有导入第三方jar包 这时候打包就比较简单: 1. 首先在Eclipse中打开项目, 右键点击项目,选择“Export”:2. 选择Java/JAR file,Next:3. Select the resources to export中可以选择你想要包含的项目文件夹,一些不

Hibernate多对多两种情况

Hibernate在做多对多映射的时候,除了原先的两张表外,会多出一个中间表做关联,根据中间表的会有两种不同的配置情况: 1.中间表不需要加入额外数据. 2.中间表有其他字段,需记录额外数据. 下面,我们就以address.person这两张表根据这两种情况做下相应的配置: 情况1: 我们需要建三张表,一张address表,一张person表,一张中间表(其实中间表可以不用建,配置好后运行会自动生成),如下: delimiter $$ CREATE TABLE `address` ( `addr

进行蓝牙连接的两种方式

为了在两台设备间创建一个连接,必须实现服务器端和客户端的机制,因为一个设备必须打开一个Server Socket,而另一个必须发起连接(使用服务器端设备的MAC地址发起连接).当服务器端和客户端在同一个RFCOMM信道上都有一个BluetoothSocket时,则两端就建立了连接.此刻,每个设备都能获得一个输入输出流,进行数据传输.服务器端和客户端获得BluetoothSocket的方法是不同的,服务器端是在客户端的连接被接受时才产生一个BluetoothSocket,客户端是在打开一个到服务器

mysql乱码的两种情况

对于MySQL数据库的乱码问题,有两中情况: 1. mysql数据库编码问题(建库时设定). 2. 连接mysql数据库的url编码设置问题. 对于第一个问题,目前个人发现只能通过重新建库解决,建库的时候,选择UTF-8字符集.我试过修改现有数据库字符集为UFT -8,但是根本不起作用,插入的中文仍然乱码(中文显示成:???).重建库时选择字符集为UTF-8之后,中文正常显示了. 对于第二个问题,是这样的情况:我建库时设置了数据库默认字符集为UTF-8,通过mysql workbench直接插入

web.config中配置数据库(多数据)连接的两种方式

这是我的第一篇文章,既然是第一篇了,那就从最基础的只是说起--web.config中配置数据库连接. 网上有很多这方面的资料,但发现并没有一篇从头到位很清楚明了说完的,今天就把我的整理写在这里吧. 在网站开发中,数据库操作是经常要用到的操作,ASP.NET中一般做法是在web.config中配置数据库连接代码,然后在程序中调用数据库连接代码,这样做的好处就是当数据库连接代码需要改变的时候,我们只要修改web.config中的数据库连接代码即可,而不必在修改每一个页面中的数据库连接代码. 在ASP

启动多线程的两种情况比较

启动多线程有两种方式:(都是在主线程main线程下) 1. 使用同一个线程对象来启多个线程 2. 使用多个线程对象来启多个线程 这两种方式有什么区别呢?先贴上代码举例说明: 这是使用线程对象MyRunnable的同一个实例r来启动了两个线程 MyRunnable r = new MyRunnable(); Thread ta = new Thread(r,"Thread-A"); Thread tb = new Thread(r,"Thread-B"); ta.st