关于libuv接收大于指定长度数据包
libuv接收数据:uv_alloc_buf分配多少大小内存空间,就接收多少大小的数据
uv_read_start
static void uv_connection(uv_stream_t* server, int status){
uv_session* uv_s = uv_session::create();
uv_tcp_t* client = &uv_s->tcp_handler;
memset(client, 0, sizeof(uv_tcp_t));
uv_tcp_init(uv_default_loop(), client);
client->data = (void*)uv_s;
uv_accept(server, (uv_stream_t*)client);
struct sockaddr_in addr;
int len = sizeof(struct sockaddr_in);
uv_tcp_getpeername(client, (sockaddr*)&addr, &len);
uv_ip4_name(&addr, (char*)uv_s->c_address, 32);
uv_s->c_port = ntohs(addr.sin_port);
uv_s->socket_type = (int)server->data;
printf("new client commings %s:%d\n", uv_s->c_address, uv_s->c_port);
uv_read_start((uv_stream_t*)client, uv_alloc_buf, after_read);
}
uv_alloc_buf
static void uv_alloc_buf(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf){
uv_session* s = (uv_session*)handle->data;
printf("收到字节数为%d\n", s->recved);
if (s->recved < RECV_LEN){
*buf = uv_buf_init(s->recv_buf + s->recved, RECV_LEN - s->recved);
}
else{
if (s->long_pkg == NULL){
int pkg_size;
int head_size;
if (s->socket_type == WS_SOCKET && s->is_ws_shake){
ws_protocol::read_ws_header((unsigned char*)s->recv_buf, s->recved, &pkg_size, &head_size);
s->long_pkg_size = pkg_size;
s->long_pkg = (char*)malloc(pkg_size);
memcpy(s->long_pkg, s->recv_buf, s->recved); //把原来存的数据移动到long_pkg里面
}
else{
//TCP_SOCKET处理
tcp_protocol::read_header((unsigned char*)s->recv_buf, s->recved, &pkg_size, &head_size);
s->long_pkg_size = pkg_size;
s->long_pkg = (char*)malloc(pkg_size);
memcpy(s->long_pkg, s->recv_buf, s->recved); //把原来存的数据移动到long_pkg里面
}
}
*buf = uv_buf_init(s->long_pkg + s->recved, s->long_pkg_size - s->recved);
}
}
after_read
static void after_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf){
uv_session* s = (uv_session*)stream->data;
if (nread < 0){
s->close();
return;
}
s->recved += nread;
if (s->socket_type == WS_SOCKET){ //websocket
if (s->is_ws_shake == 0){ //没有握手
if (ws_protocol::ws_shake_hand((session*)s, s->recv_buf, s->recved)){
s->is_ws_shake = 1; //握手成功
s->recved = 0;
}
}
else{ //已经握手,可以收发数据了
on_recv_ws_data(s);
}
}
else{ //tcpsocket
on_recv_tcp_data(s);
}
}
on_recv_ws_data接受数据后,如果收到的数据大于RECV_LEN定义的最大长度,比如定义最大长度RECV_LEN为10,但是却收到了15个字节数据,uv_alloc_buf分配多少长度,libuv内存就收到多少数据
Libuv收数据是这样的流程
第一步:如果有用户首次发数据过来(158888888888888159999999999999),就会首先触发uv_alloc_buf函数,这个时候收到的数据s->recved = 0,所以就会分配一个RECV_LEN(10)长度的内存s->recv_buf
第二步:等uv_alloc_buf分配完成内存后,触发after_read函数,接受数据,把数据保存到uv_alloc_buf分配的内存中去,这个时候只收到了10个字节的数据为(138888888888888)s->recved = 10,数据包长度pkg_size = 15,只收到了10字节后面还有5个字节没有收到,把数据放到s->recv_buf内存中
第三步:剩余用户发送的数据,会再次触发一次uv_read_start函数,通过uv_alloc_buf再次分配内存这个时候,s->recved < RECV_LEN 为 FALSE,就分配了s->long_pkg,从数据中读取数据包长度pkg_size为15(假设),就分配s->long_pkg的长度为15,把数据从s->recv_buf复制到s->long_pkg中
第四步:再次进入到after_read函数中s->recved = 15,再次读取数据包体长度为pkg_size = 15,处理完成后s->recved - pkg_size = 0,如果(s->recved == 0 && s->long_pkg != NULL),就把s->long_pkg内存释放掉,这样每次s->long_pkg只会处理一个完成的数据包,就不会存在收到多个大于RECV_LEN长度的数据包
第五步:下次再次接收数据的时候,就会重新分配s->recv_buf;