ascs demo解释(五):file_client + file_server

31 篇文章 0 订阅
31 篇文章 1 订阅

QQ交流群:198941541

file_client演示了运行时替换解包器,这是这篇文章的重头戏。首先,为什么要运行时替换解包器,那是因为我们在传输文件之前是命令模式,消息是有协议的,到了文件传输的时候,我们切换到传输模式,消息是流式无协议的,这两种情况下,解包器是完全不一样的,ftp传输也采用类似的办法,只是它把命令和数据分在了不同的连接上进行。为了运行时替换解包器,必须定义宏ASCS_PASSIVE_RECV,这个宏的意思是由使用者触发消息的接收(异步的),连接建立起来之后的第一次接收除外。所以大家可以看到,在on_msg,on_msg_handle里面都有recv_msg调用(不定义宏ASCS_PASSIVE_RECV的话,recv_msg不可访问),替换解包器必须要在recv_msg之前,替换之后,老的解包器将被释放,你不应该保留解包器里面的任何指针或者引用,否则就要注意在替换解包器之后,它们会变成野指针。替换解包器代码为:

unpacker(std::make_shared<file_unpacker>(...));

这里的file_unpacker就是新的解包器,它和默认解包器都继承自i_unpacker<std::string>,所以可以替换。file_unpacker直接在parse_msg里面处理消息(写入文件),并不返回任何消息,然后回到on_msg或者on_msg_handle里面再次调用recv_msg,注意,如果定义了宏ASCS_PASSIVE_RECV,当解包器未出错但一个消息也没返回时,ascs会自动添加一个空消息到接收队列(因为我们需要派发空消息来触发下一次recv_msg调用),我们需要一个空消息用来在handle_msg函数里面判断接收是否完毕:

	void handle_msg(out_msg_ctype& msg)
	{
		if (TRANS_BUSY == state)
		{
			assert(msg.empty());

			auto unp = std::dynamic_pointer_cast<file_unpacker>(unpacker());
			if (!unp || unp->is_finished())
				trans_end();

			return;
		}
        ...
    }

但如果定义了宏ASCS_SYNC_DISPATCH,ascs并不会自动添加空消息,所以在on_msg里面,如果msg_can为空,我们新建了一个空消息用来调用handle_msg。数据接收完毕之后,将解包器换回到默认解包器,并进入下一轮(命令模式)。

unpacker(std::make_shared<ASCS_DEFAULT_UNPACKER>());

下面看看file_server,它也工作在两种模式之下,但它不需要替换解包器,因为它只会解命令然后发送文件内容,不会接收流式数据;它也不需要替换打包器,因为只有命令模式下才需要打包,传输模式下无需打包,当然你也可以写一个流式数据打包器,但在file_server这种情况下,显得有点多余,我们可以直接发送消息(direct_send_msg),为此我们必须让命令模式下的打包器生成的数据类型,与调用direct_send_msg时的数据类型一样,所以我们用了这个打包器:#define ASCS_DEFAULT_PACKER packer2<>,它生成的消息类型是unique_buffer<i_buffer>,direct_send_msg时,我们生成的消息类型是in_msg_type(new file_buffer(...)),可以看到,file_buffer是继承自i_buffer,所以它们的消息类型都是unique_buffer<i_buffer>。那么当一个消息发送成功,要发送下一个时,如何知道当前是命令模式还是传输模式呢?可以如下:

void file_socket::on_msg_send(in_msg_type& msg)
{
	auto buffer = dynamic_cast<file_buffer*>(&*msg.raw_buffer());
	if (nullptr != buffer)
	{
		buffer->read();
		if (buffer->empty())
			trans_end();
		else
			direct_send_msg(std::move(msg), true);
	}
}

packer2<>生成的消息,真实类型是ascs::ext::string_buffer,虽然也继承自i_buffer,但它不可能成功转成file_buffer。更正:最新的file_server已经支持文件接收(这样才合理,任何一个文件传输工具,都支持类似put和get,之前只支持get),那么file_server也需要替换解包器,实现方式和file_client差不多,可以参考,这里就不再赘述。

注意:demo主要还是演示运行时替换解包器,并不是演示最高效率,我们可以讨论一下如何提高file_client + file_server的效率,首先可以用内存映射,解包器返回的缓存直接就是内存映射,写满再换到下一片(如果文件太多一次映射不完的话),无需再解包,相当于让API recv直接写入文件,我收费为网友实现过类似的,效率高许多(由于收了费,就不能把源代码放出来)。其次我们可以考虑让文件读写与socket数据收发并行,那至少宏ASCS_PASSIVE_RECV就不能定义了,它是处理完消息再发起下一次数据读取。

上一篇:ascs demo解释(四):pingpong_client + pingpong_server, socket_management

下一篇:ascs demo解释(六):其余demo

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值