如何做一个国产数据库(四)

网络

这次要用到网络了,存储的时候我们都使用网络来输入输出,当然,像本机是可以使用进程间通信的,不过为了简单,我们此次都使用tcp协议。

协议

此次使用libuv来做网络的传输,我们首先定一个协议,做到能订阅发布

//协议

//第1字节 0-1位 总共2位
//00 发布数据
//01 订阅数据
//10 心跳数据
//11

// 第一字节 2-5位 总共4位
// 0000 json数据
// 0001 二进制数据
// 0010 文本数据
// 0011 视频数据
// 0100 音频数据
// 0101 标注数据
// 0110 sql语句
// 0111 命令包
// 1000 其他
// 第一字节 2 位
//00
//01
//10
//11
//第2字节 库标识长度 0 代表没有
//第3-6字节 共4个字节 数据长度
// 数据内容 (库标识符+数据内容)

//其他
//如果第2字节库标识符不为0,则取长度,因为用1个字节
//所以库标识符最长为255个字节,此为限定。
//库字符串示例:table1/1001

show me the code

以下为tcp的server,我们使用libuv来制作这个server,做到能够订阅发布,暂时是框架,原理就是:
先接包头,再接包体,循环进行,不断地收包

class tcp_server
{
	//包头和包体的
	tcp_settings _set;

	uv_tcp_t * _server = NULL;
public:
	tcp_server(){}
	~tcp_server() {}
protected:
	//客户端断开连接
	static void on_close(uv_handle_t* handle) {
		//客户端下线
		client_t* client = (client_t*)handle->data;
		client->clean();
		delete client;
		//client_offline(client->deviceid);
	}

	

	static void alloc_cb(uv_handle_t * handle, size_t suggested_size, uv_buf_t* buf) {
		int buflen = 0;
		int headlen = 0;
		int bodylen = 0;
		client_t* client = (client_t*)handle->data;
		char *head = &(client->head[0]);     //数据接收的头部
		char *pos = head + client->recvlen; //位置指向数据已经接收的下一个字节
		//得到头部长度
		headlen = get_headlen(client->config);
		if (client->status == enum_head) //接收头部字节
		{
			buflen = headlen - client->recvlen;
			*buf = uv_buf_init(pos, buflen);
		}
		else  //接收数据部分字节
		{
			//得到包体长度
			bodylen = get_bodylen(client->config, head); 
			//printf("the body len is %d\n", bodylen);
			if (bodylen > 0) {
				if (client->buffer_data == NULL) {
					//总长度
					//printf("create memory\n");
					client->buffer_data = new tcp_unit();
					//加上头部长度
					client->buffer_data->headlen = headlen;
					client->buffer_data->data = new char[bodylen + headlen];
					client->buffer_data->tlen = bodylen + headlen;
					//数据接收的长度加上头部的长度,开始接收数据体
					client->buffer_data->recvlen = headlen;
					//拷贝头部
					memcpy(client->buffer_data->data, head, headlen);
					*buf = uv_buf_init(client->buffer_data->data + headlen, bodylen);
				}
				else {
					//前面加了头部
					char * pos = client->buffer_data->data + client->buffer_data->recvlen;
					buflen = client->buffer_data->tlen - client->buffer_data->recvlen;
					*buf = uv_buf_init(pos, buflen);
				}
			}
			else { //否则没有包体,只有包头
				client->buffer_data->tlen = bodylen;
				client->buffer_data->recvlen = 0;
			}
		}

	}
	//


	
	static void worker(uv_work_t* req) {		
		thread_work * rb = (thread_work *)req->data;
		tcp_unit *tu = rb->data;

		tcp_server *server =(tcp_server*)rb->client->data;
		server->on_data(tu);
	}
	static void after_worker(uv_work_t* req,int status) {

		thread_work *work = static_cast<thread_work *>(req->data);
		tcp_unit * tu = work->data;
		free(tu->data);
		free(tu);
		free(work);
		
	}
	static int tcp_parser_execute(client_t* client, char *data, int size)
	{
		int headlen = 0;
		headlen = get_headlen(client->config);
		if (client->status == enum_head)
		{
			client->recvlen += size;
			//如果头部字节已经接收完毕
			if (headlen == client->recvlen)
			{
				client->status = enum_body; //开始接收包体数据
				//头部已经接收完毕则发生事件
				//继承加入可以发生事件,如加入列表
				tcp_server * server = (tcp_server *)client->data;
				server->on_headers_complete(client);
			}
		}
		else if (client->status == enum_body)
		{
			client->buffer_data->recvlen += size;
			if (client->buffer_data->tlen == client->buffer_data->recvlen) {//数据已经接收完毕
																			//包头数据初始化
				client->recvlen = 0;
				client->status = enum_head; //开始重新接收包头
				if (client->buffer_data->tlen > 0) {
					//发生事件
					tcp_server * server = (tcp_server *)client->data;
					server->on_message_complete(client);

					thread_work * work = new thread_work(client,client->buffer_data);
					work->id = client->deviceid;
					client->buffer_data = NULL;

					//消息体接收结束,交给线程池处理
					int status = uv_queue_work(client->config->uv_loop,
						&work->request,
						worker,
						after_worker);
					
				}
			}
		}
		return client->recvlen;

	}

	static void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t * buf) {
		ssize_t parsed;
		client_t* client = (client_t*)tcp->data;
		if (nread >= 0) {
			parsed = (ssize_t)tcp_parser_execute(
				client, buf->base, nread);
			if (parsed < 0) {
				printf("parse error");
				//tcp_parser *parser = &client->parser;
				
				uv_close((uv_handle_t*)&client->tcp, on_close);
			}
		}
		else {
			if (nread != UV_EOF) {
				//log here
			}
			uv_close((uv_handle_t*)&client->tcp, on_close);
		}

	}

	static void on_connect(uv_stream_t* server_handle, int status) {
		//CHECK(status, "connect");
		printf("connected!\n");
		tcp_server * server  = (tcp_server *)server_handle->data;
		client_t* client = (client_t*)calloc(1, sizeof(client_t));
		client->config   = &(server->_set);
		//这里还没有改成读json文件,后面停用脚本文件
		//client->config2  = &(server->_set2);
		client->data     = server;
		uv_loop_t * uv_loop = client->config->uv_loop;

		uv_tcp_init(uv_loop, &client->tcp);

		client->tcp.data = client;

		int r = uv_accept(server_handle, (uv_stream_t*)&client->tcp);
		if (r == 0) {
			uv_read_start((uv_stream_t*)&client->tcp, alloc_cb, on_read);
		}
		else {
			//CHECK(r, "accept");
			uv_close((uv_handle_t*)(&client->tcp), on_close);
		}
	}



public:
	//头部接收完毕
	virtual int on_headers_complete(void *param) {
		return 0;
	}

	virtual int on_message_complete(void *param) {
		return 0;
	}
	//收到完整一帧数据
	virtual int on_data(tcp_unit * data) {
		return 0;
	}
	int start(const char * ip, uint16_t port) {
		int r = uv_tcp_init(_set.uv_loop, _server);
		//保存用户数据,是tcp server 本身指针
		_server->data = this; // &_set;
		r = uv_tcp_keepalive(_server, 1, 60);
		struct sockaddr_in address;
		r = uv_ip4_addr(ip, port, &address);
		r = uv_tcp_bind(_server, (const struct sockaddr*)&address, 0);
		r = uv_listen((uv_stream_t*)_server, MAX_WRITE_HANDLES, on_connect);

		//tcp_servers.push(port, server);
		return 0;

	}
	int  tcp_init(const char* configfile, uv_loop_t* uv_loop)
	{
		//fix me ,here is not use configfile
		_server = new uv_tcp_t();
		_set.uv_loop = uv_loop;

	}
	void uninit()
	{
		free(_server);
	}

	//得到所有的客戶端ip地址和流量等数据
	int getclients()
	{
		return 0;
	}
	client_t *getclient(uint32_t deviceid) {
		return NULL;
	}

};

以上暂时为框架,等待后续。。。

你可能感兴趣的:(笔记,c++,db,架构设计,libuv,数据库协议)