如何做一个国产数据库(六) 网络传输 nodejs做测试客户端

39 篇文章 2 订阅
11 篇文章 0 订阅

如何做一个国产数据库一
如何做一个国产数据库二
如何做一个国产数据库三
如何做一个国产数据库四
如何做一个国产数据库五

网络实战服务器

我们再四中说过使用tcp进行协议的链接,对我们所定义的协议如果有不清楚的,我们可以再看一下四,示例使用libuv进行服务器编程,uv是一个异步网络库。

除了协议,再次定义一下我们网络的数据结构

//客户端数据结构
typedef struct client_t {
	//tcp client session
	uv_tcp_t tcp;
	//解析使用
	tcp_settings * config = NULL;
	//写入
	uv_write_t write_req;


	//设备id
	uint32_t   deviceid = 0;
	//读入的内容
	tcp_unit   *buffer_data = NULL;
	
	//需要写入的内容
	tcp_unit_w *buffer_data_w = NULL;
	
	//最长6字节包头
	char head[6];
	//已经接收的头部的长度
	int recvlen;

	//用户自定义数据指针 tcpserver
	void * data = NULL;
	
	//接收状态 接收头部,0 接收数据 1
	recv_status status = enum_head; 

	//是否在线
	int is_online = enum_online;

	uv_timer_t  _timer;
	uv_thread_t _thread;


	int thread_run = 0;

	int time_init() {
		if (config == NULL)
			return -1;
		uv_timer_init(config->uv_loop, &_timer);
		return 0;
	}

	client_t() {
	}

	void clean()
	{
		free_unit(&buffer_data);
	}
	int headlen() {
		return recvlen;
	}
}client_t;

工作队列数据结构

typedef struct thread_work {
	thread_work(client_t* cli, tcp_unit * unit) :
		request(),
		client(cli),
		data(unit),
		error(false) {
		//保存数据指针,传到处理线程
		request.data = this;
	}
	uint32_t id =0;
	client_t* client = NULL;
	//把数据接过来进行处理
	tcp_unit * data = NULL;
	uv_work_t request;
	bool error;
}thread_work;

根据我们所定义的协议,如何从包头中取出包体的长度?是第二个字节加上后面四个字节的网络字节序反转成h字节序,就成了包体长度,接下去就是获取包体的过程。

static uint32_t get_bodylen(tcp_settings * setting, char *head)
{
	//headlen_offset 是偏移量+1
	int len1 = *(head + 1);
	char *b = head + 2;
	return len1+ntohl(*(uint32_t*)b);
}

上一篇里面已经写了一个tcpserver,小有改动,将body里面的内容去除包头,因此tcpunit的数据结构修改了一下:

typedef struct tcp_unit
{
	//真实数据
	char * bodydata = NULL;
	//数据总长度bodylen + headlen
	int bodylen = 0;
	//接收到的数据长度
	int recvlen = 0;
	//头部长度
	int headlen = 0;
}tcp_unit;

一切就绪,接下去就是定义一个真正的接收数据的server,从我们第四章里面的tcpserver继承下来:

class tcp_server1 :public tcp_server
{
	//所有客戶端,用四字节整形数作为hash key
	std::unordered_map<uint32_t, client_t*>  v_map_c;
	uv_mutex_t  _mutex_1;
public:
	tcp_server1() {}
	~tcp_server1() {}
protected:
	uint32_t getid(client_t* client)
	{
		return 0;
		/*tcp_settings* cnf = client->config;
		char* idpos = &client->head[0] + cnf->idoffset;
		uint32_t deviceid = htonl(*((uint32_t*)idpos));
		///((deviceid >> 16) & 0xff00) | deviceid >> 24
		return deviceid;*/
	}
public:



	int on_headers_complete(void* param) {
		//client_t* pclient = (client_t*)param;

		printf("the header len is %d\n", pclient->recvlen);
		//printf("the id is %04x\n", getid(pclient));
		return 0;
	}
	//该函数没有进入线程池
	int on_message_complete(void* param) {
		client_t* pclient = (client_t*)param;
		tcp_unit* data = pclient->buffer_data;
		//char* buf = data->data;
		//int len = data->tlen;
		//printf("the total len is %d\n", pclient->buffer_data->tlen);
		return 0;
	}
	//该函数进入线程池
	int on_data(tcp_unit* data) {
		//printf("the thread pid is %d\n", _getpid());
#ifdef _DEBUG
		int hl = data->headlen;
		//printf("the hl is %d\n", hl);
		//for (size_t i = hl; i < hl + 8; i++) {
		//	printf("%02x ", (uint8_t)data->data[i]);
		//}
		string test(data->bodydata, data->bodylen);
		printf("the data is %s\n", test.c_str());
		//printf("the len is %d\n", data->bodylen);
#endif



#if 0
		//给客户端回送信息

		tcp_unit_w* unitw = (tcp_unit_w*)malloc(sizeof(tcp_unit_w));
		unitw->delay = 0;
		unitw->data = (char*)malloc(sizeof(char) * 18);
		memcpy(unitw->data, buf, 18);
		unitw->len = 18;
		unitw->next = NULL;
		unitw->type = enum_sc;
		client_send(rb->id, unitw);
		//解析成为json发送到相应的接口
		string response;
		int timeout = 2; //2秒
						 //post是同步的

						 /*	bool ret = client.Post("http://127.0.0.1:9069/sensor_data/8052", buf, len, response, timeout);
						 if (ret == false) {
						 printf("error!:%s\n", client.geterror().c_str());
						 }
						 printf("response:%s\n", response.c_str());*/
#endif
		return 0;
	}


};

客户端定义

我们后面做sdk的时候,将会分别使用java,node,go,c++,等来做客户端链接,其中又属nodejs是最简单不过的,我们先使用nodejs来做一个客户端:

var net = require('net');
var HOST = '127.0.0.1';
var PORT = 8054;
var client = new net.Socket();



var step = 0.01;
function test_8053() {
    const buftemp = Buffer.allocUnsafe(4 + 2 + 6 + 12);
    buftemp[0] = 0; //
    buftemp[1] = 1; //
    buftemp[2] = 0; //
    buftemp[3] = 1; //设备编号
    buftemp[4] = 1;//命令字
    buftemp[5] = 24;  //包体长度
    buftemp[6] = 0;// 正常待机,正常下锤探测,第一次首盘探测,过程反复探测,顶部到位反复探测,故障停机
    buftemp[7] = 0; //故障字
    buftemp[8] = 1; //警示字1
    buftemp[9] = 1;//警示字2
    buftemp[10] = 10; //电池电量
    buftemp[11] = 0;//备用
    step += 0.01;
    buftemp.writeFloatBE(12.90 +step , 12);
    buftemp.writeFloatBE(13.4 + step, 16);
    buftemp.writeFloatBE(34.5 +step, 20);
    client.write(buftemp);

    setTimeout(test_8053,5000);
}


//flv server, 4 bytes length,after is body
var xflag = 0x61;

function test_8054() {
    const buftemp = Buffer.allocUnsafe(19);
    buftemp[0] = 0;
    buftemp[1] = 6;
    //网络字节序一般指大端
    buftemp.writeInt32BE(7, 2);
	buftemp.write("qianbo",6);
	buftemp.write("{a:\"b\"}",12);
	client.write(buftemp);
	setTimeout(test_8054, 1000);
}

function closesocket() {
    // client.end();
    console.log("please close me");
}


client.connect(PORT, HOST, function () {

    console.log('CONNECTED TO: ' + HOST + ':' + PORT);
    // Write a message to the socket as soon as the client is connected, the server will receive it as message from the client 

    else if (PORT == 8054)
        test_8054();
    //setTimeout(test_8053, 1000);
});

// Add a 'data' event handler for the client socket
// data is what the server sent to this socket
client.on('data', function (data) {

    console.log(data);
    //client.destroy();
});

// Add a 'close' event handler for the client socket
client.on('close', function () {
    console.log('Connection closed');
});

结果:

如下图,我们启动服务器在端口8054等待客户端链接,连接后打印出connected,客户端发送数据后,我们显示出,数据库表名为:qianbo, 数据字段为一个json:{a:“b”}
在这里插入图片描述
ok,目前位置,我们将数据传了过去,至于为什么nodejs里面第一个字节为全0,大家可以看我的协议定义,第二个字节长度为6,因为数据库名称长度为6,—>qianbo,.并且根据协议,nodejs的客户端为发布客户端,此次网络实战结束,后面会把接收到的数据存储,以供其他客户端订阅。待续。。。。。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qianbo_insist

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值