關於libuv接收大於指定長度資料包
關於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;