当前位置:C++技术网 > 精选软件 > libuv服务器端包装类源代码升级:支持合并多次连续发包

libuv服务器端包装类源代码升级:支持合并多次连续发包

更新时间:2017-06-05 17:57:48浏览次数:1+次

        在文章《libuv服务器端包装类源代码分享(修正Linux服务器连续死循环版)》中,我已经修复了Linux系统下的连续回复发送问题。而此前在没有找到问题前,则是采用绕过去的方法来规避问题。既然连续多次回复会出问题,那么我将多次回复合并到一个数据包发送出去,不就只有一次发送了嘛。所以就实现了这个功能。这个功能在连续回复数据时表现还可以,只是遇到不得不多次发送时才没有办法,这也是解决Linux下Libuv死循环的原因。因为实在绕不过去,就必须直接面对问题,进而解决问题咯。

        不过这个合并发送数据,也是很有用的。在需要频繁的连续多次发送数据时,则会因为频繁的发送而降低性能。将多个数据包合并到一个数据包中,底层在发送时将会采用最合适的大小发送,进而可以提升网络性能。每一次发包时,数据包都会加上各种协议的包头包尾,这样也增加了传输的数据量。

        同时,每次启动发送当然也消耗性能。所以这个好处是不言而喻的。当然,如果只是偶尔的一两次合并,对于效率就没有什么影响,反而让编程变得复杂,容易带入Bug。

       合并数据的基本思路是:在发送数据的函数send中,定义一个参数is_send,如果为true,则立即发送数据,如果为false,则将数据缓存起来。比如要发送4个数据包,那么前面三个数据包发送时传入fasle,第四个数据包则传入true,这样最后一个数据包就会将所有数据一次性的发出去了。

       使用场景距举例:客户端向服务器发送签到命令,服务器自然要回复签到是否成功。然后服务器还要回复一些其他相关的信息,特别是回传的信息在很多个命令的时候,比如费率、对时、服务器信息等,这样合并到一起就可以将本来要连续回复很多条数据瞬间变成一条数据发出去。很多设备使用的是3G/4G网络,需要消耗流量,如果合并发送,一方面可以提高性能,而且可以省流量,可以提升体验哦。

        升级说明:升级的代码只给出关键代码,其他代码见文章开头的文章链接的完整代码,自己加一下就行了。

    1.在CTcpServer类声明中加入两个变量,作为缓冲区和缓冲区大小

    

char * m_pbuf_send;//叠包发送的缓冲区
size_t m_buf_send_size;//叠包发送的缓冲区大小
2.在类对象的构造函数中初始化缓冲区

    

    

CTcpServer::CTcpServer(uv_loop_t* loop)    :newconcb_(nullptr), isinit_(false)
{
 loop_ = loop;
 m_pbuf_send = 0;
 m_buf_send_size = 0;
}
3.升级后的send函数,缓冲区关键代码

    

    

int CTcpServer::send(int clientid, const char* data, std::size_t len,bool is_send)
{
 char *data_tmp=0;
 if (!m_pbuf_send)
    {
        //没有使用缓冲区
        m_pbuf_send = new char[len];
        m_buf_send_size = len;
        memcpy(m_pbuf_send, data, len);
    }
    else
    {
        //已经缓冲了数据
        size_t buf_new_size = m_buf_send_size + len;
        char * ptmp = m_pbuf_send;
        m_pbuf_send = new char[buf_new_size];
        memcpy(m_pbuf_send, ptmp, m_buf_send_size);
        memcpy(m_pbuf_send + m_buf_send_size,data,len);
        m_buf_send_size = buf_new_size;
        delete[] ptmp;
    }
    if (!is_send)
    {
        //不直接发
        return 0;
    }
    else
    {
        //直接发送
        data_tmp = m_pbuf_send;
        len = m_buf_send_size;
    }

    
    //服务器发送数据给客户端函数 
 auto itfind = clients_list_.find(clientid); 
 //找不到指定ID的客户端 
 if (itfind == clients_list_.end()) return -1; 
 //自己控制data的生命周期直到write结束 
 if (itfind->second->writebuffer.len < len) 
 { 
 itfind->second->writebuffer.base = (char*)realloc(itfind->second->writebuffer.base, len); 
 itfind->second->writebuffer.len = len; 
 } 
 memcpy(itfind->second->writebuffer.base, data, len); 
 uv_buf_t buf = uv_buf_init((char*)itfind->second->writebuffer.base, len); 
 uv_write_t *write_req1 = new uv_write_t;//在回调函数AfterSend中会释放[修复点:新增] 
 int iret = uv_write(write_req1, (uv_stream_t*)itfind->second->client_handle, &buf, 1, AfterSend);[修复点:修改] 
 
 if (iret)return 1;//失败
 delete[] m_pbuf_send;//自己分配,自己释放
 m_pbuf_send = 0;
 m_buf_send_size = 0;
 return 0; 
}

    

        请自己动手,将关键代码更换到完整的代码中,如果你不想用这个,就用原代码就行了。