sogou / workflow

C++ Parallel Computing and Asynchronous Networking Framework

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

workflow自定义协议如何分包发送消息

oceanfan1990 opened this issue · comments

现在有一个场景如下:
1.利用workflow自定义了一个通信协议,协议不仅是一发一收,可以是一发多收;
如:客户端发送 数据请求,发送报文如下: 0a 00 00 00 00 00;
服务端需要发送数据回复,发送报文如下 :a. 0b 00 00 00 00 00; b. 0a 00 00 00 00 ...
即是客户端发送了 数据请求, 服务端需要首先回复 数据确认报文a, 然后再回复数据应答报文b.

  如果数据应答报文的长度过长,还需要进行固定长度的分割,再分包发送;

我参考了一下workflow的文档,我自己的做法如下,但是有问题:贴出代码如下:

//just for test
void timer_callback(WFTimerTask *timer)
{
    printf("Finished. Press enter to end.\n"); 

	SeriesWork *series = series_of(timer);

	dl476_series_context *context = (dl476_series_context *)series->get_context();
	auto *proxy_resp = context->dl476_task->get_resp();
	int into = context->into;
	std::string filename = context->filename;

	int filename_size = filename.size();
	int err = -1;
	if(err == -1)  //NOTE 文件没有更新
	{
		int size = 23 + filename_size + 1;

		int time = 1721284510;  //

		uint8 * cacheBuf = (uint8 *)malloc(size);
		if(!cacheBuf)
			return;

		int len = 17 + filename_size;

		cacheBuf[0] = A_DATA;	//控制域 不需要扩展
		cacheBuf[1] = 0;		//运行模式,0型规程,00010000
		cacheBuf[2] = 0;		//状态标识
		cacheBuf[3] = 0;		//原因码
		cacheBuf[4] = len % 256;		//参数域长度,不需要扩充参数
		cacheBuf[5] = len / 256;

		cacheBuf[6] = 42;
		cacheBuf[7] = 0;

		int i = 8;
		cacheBuf[i] = 0;
		cacheBuf[++i] = 0;
		cacheBuf[++i] = 0;
		cacheBuf[++i] = 0;
		cacheBuf[++i] = 0;
		cacheBuf[++i] = 0;
		cacheBuf[++i] = 0;
		cacheBuf[++i] = 0;

		//时间赋值
		util::timedecode(&cacheBuf[++i], time);
		i += 7;
		memcpy(&cacheBuf[i], filename.data(), filename_size);
		i += filename_size;

		proxy_resp->set_message_body(cacheBuf, i);
		free(cacheBuf);
	}
	else if(err == 0)  //NOTE 文件有更新
	{
		std::string t_file = "util.cc";
		std::string t_filetext;
		std::size_t t_filesize;
		util util_obj;
		t_filesize = util_obj.readfiletostring(t_file, t_filetext);

	}

	delete (dl476_series_context *)series->get_context();

}

void process(WFDl476Task *task)
{
	printf("address %x\n", task);

	//获取客户端ip信息,如果客户端ip非法,则断开连接
	std::string ipstr;
	int port;
	util::getipinfofromtask(task, ipstr, port);
	auto search = g_ipset.find(ipstr); 
	if(search == g_ipset.end())
	{
		printf("illegal client ip : %s, port : %d server will close it\n", ipstr.data(), port);
		task->set_keep_alive(1 * 1000);
	}
		
	Dl476Request *req = task->get_req();
	Dl476Response *resp = task->get_resp();
	uint8 *body;
	size_t size;

	req->get_message_body_size(&size);
	printf("size : %ld\n", size);

	body = (uint8 *)malloc(size);
	req->get_message_body_nocopy(&body, size);

	struct RequestInfo reqinfo;
	int ret = resp->message_body_parser(body, size, reqinfo);
	if(ret == 1)   //NOTE 约定: 返回值0代表非数据请求, 1代表数据请求
	{
		resp->dl476_dataack_reply(A_DATA_ACK); //TODO 收到数据请求,首先回复数据确认

		task->set_callback([&, reqinfo](WFDl476Task *server_task){

			//获取上下文,执行异步任务,并且把异步任务获取的结果返回
			SeriesWork *series = series_of(server_task);
			dl476_series_context *context = new dl476_series_context;
			context->dl476_task = task;
			context->into = reqinfo.into;
			context->filename = reqinfo.filename;

			series->set_context(context);

			switch (reqinfo.type)
			{
				case RequestType::ftp :
				{
					//just for test
					WFTimerTask *timer = WFTaskFactory::create_timer_task(1000000, timer_callback);
					series->push_back(timer);

				}
				break;
				case RequestType::display :
				{

				}
				break;
				case RequestType::stopdata :
				{

				}
				break;	
			default:
				break;
			}
			// delete (dl476_series_context *)series->get_context();
		});
	}

    free(body);
	printf("\nexist process\n");
}

这样做,是可以首先发送数据确认报文了,但是数据应答报文却发送不出了;是不是因为 进入callback之后,原本的task的生命期就结束了,所以timer_callback中获取到series中的task不是原来的task,导致发送不出?

我要怎么样做才能做到服务端可以分包发送回复?而且分包的大小可以调整?

或许这个问题可以利用task的push接口;测试代码可以改为:

uint8 cacheBuf[4];
		cacheBuf[0] = A_DATA_ACK;	//控制域 不需要扩展
		cacheBuf[1] = 0;		
		cacheBuf[2] = 0;		
		cacheBuf[3] = 0;	

		task->push(&cacheBuf, 4);	

		cacheBuf[0] = A_DATA_NAK;	//控制域 不需要扩展
		cacheBuf[1] = 0;		
		cacheBuf[2] = 0;		
		cacheBuf[3] = 0;	
		task->push(&cacheBuf, 4); 

用task的push接口测试了一下,可以达到分包发送的效果;收到数据请求后,首先push一下数据确认报文,然后得到数据应答报文,分割后再调用push接口逐一发送

噢噢,你用push接口的话,要维护server_task的生命周期,只需要在series里push_back一个counter任务,直到结束时,调用counter->count()接口打开就可以了。例如:

void process(WFHttpTask *task)
{
    WFCounterTask *counter = WFTaskFactory::create_counter_task(1, nullptr);
    series_of(task)->push_back(task);
    task->noreply();

    WFTimerTask *timer = WFTaskFactory::create_timer_task(1, 0, [task, counter](WFTimerTask *timer) {
            task->push(...);
            counter->count();
    });
    timer->start();
}

不过,这个case下,其实也不需要用counter,你把timer push_back到series里就可以了。只有series不结束,server_task并不会运行到callback。

void process(WFHttpTask *task)
{
    task->noreply();

    WFTimerTask *timer = WFTaskFactory::create_timer_task(1, 0, [task](WFTimerTask *timer) {
            task->push(...);
    });

    series_of(task)->push_back(timer);
}

@Barenboim 我参考一下