1.首先定义传输协议时要包含包的长度,放在第一个位置。
2.使用一个标志标识接收到的数据长度,为0表示可以接收新的包数据。
3.在libevent源码中添加一个获取bufferevent接收数据缓冲区中有效的数据大小,加在bufferevent.c 中代码如下:
unsigned int buffer_get_validinputbyte(struct bufferevent* bufev)
{
if (!bufev)return 0;
unsigned int byteAvaliable = 0;
struct evbuffer_chain* chain = bufev->input->first;
while (chain)
{
byteAvaliable += chain->off;
chain = chain->next;
}
return byteAvaliable;
}
4.读取时判断buffer中数据是否完整,如果完整读取,参考代码:
void socket_read_cb(bufferevent* bev, void* arg)
{
struct event_base* base = (event_base*)arg;
size_t len;
// 这里一行一行的读取
char lenbuf[2] = { 0 };
evutil_socket_t fd = bufferevent_getfd(bev);
if (auto client = gDataMgr->client(fd))
{
unsigned int _byteAvaliable = buffer_get_validinputbyte(bev);
if (client->inBlockSize() == 0) //如果是刚开始接收数据
{
if (_byteAvaliable < sizeof(unsigned short)) return;
len = bufferevent_read(bev, lenbuf, 2);
if (len != 2)return;
client->setInblockSize(Utils::intergerFromStr(lenbuf,2)); //网络字节序
}
_byteAvaliable = buffer_get_validinputbyte(bev);
if (_byteAvaliable < (uint)client->inBlockSize()) return;
len = bufferevent_read(bev, client->inBlockBuffer(), client->inBlockSize());
if (len != client->inBlockSize())
{
printf("socket_read_cb::read data error!");
return;
}
client->process();
}
}
这样可以保证在client的process函数中处理的肯定是完整数据包。