热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

ascsdemo解释(五):file_client+file_server

QQ交流群:198941541file_client演示了运行时替换解包器,这是这篇文章的重头戏。首先,为什么要运行时替换解包器

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就是新的解包器,它和默认解包器都继承自i_unpacker,所以可以替换。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(unpacker());if (!unp || unp->is_finished())trans_end();return;}...}

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

unpacker(std::make_shared());

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

void file_socket::on_msg_send(in_msg_type& msg)
{auto buffer &#61; dynamic_cast(&*msg.raw_buffer());if (nullptr !&#61; buffer){buffer->read();if (buffer->empty())trans_end();elsedirect_send_msg(std::move(msg), true);}
}

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

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

上一篇&#xff1a;ascs demo解释&#xff08;四&#xff09;&#xff1a;pingpong_client &#43; pingpong_server, socket_management

下一篇&#xff1a;ascs demo解释&#xff08;六&#xff09;&#xff1a;其余demo


推荐阅读
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 本文介绍了解决Netty拆包粘包问题的一种方法——使用特殊结束符。在通讯过程中,客户端和服务器协商定义一个特殊的分隔符号,只要没有发送分隔符号,就代表一条数据没有结束。文章还提供了服务端的示例代码。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 在Java中,我会做这样的事情:classPerson{privateRecordrecord;publicStringname(){record().get(name);}p ... [详细]
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
  • 本文介绍了使用数据库管理员用户执行onstat -l命令来监控GBase8s数据库的物理日志和逻辑日志的使用情况,并强调了对已使用的逻辑日志是否及时备份的重要性。同时提供了监控方法和注意事项。 ... [详细]
author-avatar
红枫1983_1
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有