1. 程式人生 > >關於libuv接收大於指定長度資料包

關於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;