Java多线程与Socket:实战微服务框架
  • 推荐0
  • 收藏2
  • 浏览3.2K

Java多线程与Socket:实战微服务框架

庞永华 (作者) 

  • 书  号:978-7-121-36035-0
  • 出版日期:2019-03-13
  • 页  数:452
  • 开  本:16(185*235)
  • 出版状态:上市销售
纸质版 ¥99.00
本书从实战角度出发,首先介绍Java多线程、Socket、Spring、动态代理、动态字节码、序列化等技术在构建分布式微服务框架中的应用。然后介绍一种微服务框架的架构设计与编程实践,并将这一微服务框架分解为底层Socket通信、服务注册与发现、服务暴露与引用、远程方法调用等层面,逐一深入讲解。这里重点介绍作者如何活用相关技术一步步地构建微服务框架的基础RPC框架并分享了相应的性能调优经验。最后介绍微服务架构中配套的服务治理系统的设计与实现方案,包括服务的设计、配置、管理与监控。
授人以鱼不如授人以渔,作者并不希望读者通过抄写代码来编写出一模一样的东西,而是希望读者通过这一学习过程,深刻掌握Java多线程、Socket、动态代理等相关技术,最终能够做到举一反三,灵活地运用它们,从而提升自身的Java编程水平,并为进一步学习和研究Java分布式技术与微服务框架打下基础。因此,本书从相关的基础知识入手,通过剖析现有框架,讲解这些基础知识在实践中的应用,逐步将读者带入Java分布式与微服务技术领域。本书适合有一定Java基础的初中级开发人员阅读。

前言


本书适合有一定Java基础且有志成为架构师的开发人员阅读。一个优秀的架构师必须要有扎实的编程功底和丰富的理论知识,不光要能完成架构设计,更要有能力将设计转换为实际的产品。不会写代码、纸上谈兵的“架构师”设计出来的“架构”是靠不住的。因此,本书将从相关的基础知识讲起,通过剖析一个小巧精练的微服务框架的核心,介绍这些基础知识是如何在实践中被灵活、适当地运用的。
本书不是关于微服务的理论书籍,也不是某个微服务框架的使用手册。微服务涉及的范围很广,我们很难在一本书里讲清楚微服务的方方面面。
目前相关的主流框架是Spring Cloud和Dubbo。虽然Spring Cloud和Dubbo都很强大,但这个世界上从来没有最好,只有更好,因此我们永远不要停下自己创新的脚步。我们依然可以有自己的想法,并勇于尝试、付诸实践。事实上Spring Cloud和Dubbo都存在各自的问题和不足。我们通过对它们的学习和研究,站在巨人的肩膀上,吸取它们的优点再加以创新,是完全有可能做到青出于蓝而胜于蓝的。
在正式开始之前,让我们先了解一下微服务的发展背景。
面向服务的架构
1996年,Gartner公司首次提出了面向服务的架构(Service-Oriented Architecture,SOA)这一软件设计思想。其核心理念是将一个个的业务功能包装成一个个的标准服务,为这些服务定义良好的接口和服务契约,以便在需要的时候可以重用和水平伸缩。通过将这些服务进行组合和编排,可以创建新的业务流程,或者灵活地修改现有流程,以适应不断变化的业务需求,让我们的系统功能更丰富、结构更灵活、更易于扩展。同时,让系统规模能够根据需要弹性伸缩,最大限度地利用现有资产,提高效率,降低成本。总之,要使我们的系统能更灵活、更快地响应不断变化的需求。
不过,受到当时计算机水平的限制,面向服务的架构思想在诞生之初,并没有得到广泛的关注和发展。随着软件系统的规模越来越大、越来越复杂,软件系统的架构也在不断地演进,面向服务的架构开始受到人们的关注和认可。目前,大型软件系统的服务端架构多数都是面向服务的架构,或者正在朝这一架构迁移。
要明确的是,面向服务的架构中的“服务”虽然也包括系统对外提供的服务,但更多的是指系统内部的各个“模块”或“组件”的“服务化”,以及模块(服务)之间的相互调用与协同。它是“分布式”与“服务化”两个技术发展趋势合流的产物。
分布式系统
所谓的“分布式”是相对于“集中式”的一种应用系统内部组织结构。相对于传统的集中式系统(单机应用系统和集群式应用系统都属于集中式系统),分布式系统将原本集中在一个服务端应用中的功能模块拆分出来,分为多个系统组件或应用,分散部署在多个服务器上,并通过网络将它们连接起来协同工作。而客户端系统感觉不到服务端系统内部的这种变化,仍然和原来调用集中式系统一样。
分布式设计使得原本集中在单个服务器上进行的计算或存储需求被分散到了多个服务器上,从而降低了我们对单一服务器的性能要求。这样就让我们能用相对廉价的PC服务器代替昂贵的传统服务器,并通过水平扩容的方式继续提升系统的处理能力。
分布式系统并没有约定其内部的各个组件或应用之间应采用什么样的形式来实现彼此通信。早期人们使用DCOM、CORBA等技术实现组件的暴露和远程访问。这便是分布式系统的早期形态。但是这些技术比较复杂且十分笨重,只在大型系统和企业级应用中被使用。尽管之后又出现了COM+、RMI、EJB等技术,但仍然比较笨重和难用。
服务化
早期的系统都是相互独立的。受限于计算机的处理能力,其规模都比较小。比如,财务系统和人力资源管理系统分别是两个不同的系统。它们可能由不同的软件厂商,采用不同的开发语言和技术开发,并运行在各式各样的操作系统和硬件设备上。随着企业发展的需要,人们试着在两个系统间建立通信,尝试让它们彼此协同。双方的通信方式和协议由厂商之间彼此协商来制定,开发起来成本很高。各个厂商都试图制定自己的通信技术标准和协议,并力争成为业内标准。显然,如果所有厂商都遵循同一套技术标准和通信协议,就能大大地降低开发成本,让各个系统彼此更容易地互联互通。
随着基于Web的应用的普及,以及XML技术的出现和成熟,出现了基于HTTP、XML的服务暴露与远程访问方式,这就是Web Services。但Web Services的协议和实现方式很多,技术标准也多种多样。企业内部各系统之间的互联互通仍然比较麻烦。于是,企业服务总线(Enterprise Service Bus,ESB)系统被设计来实现各系统之间的服务接口适配和管理,以便各系统能够用自己熟悉的技术、标准和规范来相互调用彼此的服务。随着时间的推移,简单对象访问协议(Simple Object Access Protocol,SOAP)、Web服务描述语言(Web Services Description Language,WSDL),以及通用描述、发现与集成服务(Universal Description,Discovery and Integration,UDDI)协议逐渐成为主流的Web Services标准和规范。
后来,随着互联网技术的发展,基于HTTP RESTful的轻量级Web Services逐渐取代了基于SOAP的传统Web Services技术成为主流。由于HTTP RESTful服务暴露和调用开销比SOAP小很多,且速度更快,这就使得我们可在大型系统内部也大量使用,以作为各子系统之间,尤其是异构子系统之间最佳的通信形式。
面向服务
当我们将系统中的模块或组件服务化,代替COM+、RMI、EJB等分布式领域的组件通信技术后,系统架构就转变为面向服务的架构。当然,分布式系统中的很多组件是难以服务化的。不是所有的模块和组件都适合服务化。比如,有些模块的调用频率很高,接口复杂,转变成服务后,访问性能可能无法满足设计要求。又比如,有些模块与模块之间的耦合度较高,如果不进行重构来解耦,那么是无法单独作为服务暴露的。还有些模块的重用度不高或调用频率过低,没有服务化的必要。在对系统进行SOA改造时,一定要分析清楚。
综上所述,面向服务的架构是分布式架构中的一种。面向服务的架构一定是分布式架构,但分布式架构不一定面向服务。能够对外提供服务的系统并不一定是面向服务的架构,面向服务架构的系统也不一定对外暴露服务。
什么是微服务
顾名思义,微服务就是指粒度较小的服务。这意味着我们要对现有的分布式系统进行进一步的拆分,将其划分为更多、更小的服务来进行设计或重构。“微服务”的概念源于2014年3月Martin Fowler所写的一篇文章Microservices。它扩大了面向服务架构中“服务”的概念。不再局限于系统与系统之间的接口调用,也不局限于某种具体的服务形式。系统中凡是可被复用的功能模块都可以被“服务化”,转变为“服务”。这些服务可以对外暴露,也可能仅限于在系统内部使用。这对面向服务架构提出了更高的设计要求。由于服务数量更多、粒度更小,因此管控难度会更大,对性能的要求也更高。
那么,我们为什么要将系统拆分成一个个的微服务呢?
微服务的好处
微服务有如下好处。
1. 方便编排和重用
当我们在开发新功能时,可能需要复用现有的模块。以往我们需要将可复用的代码放到jar包中,并在工程中引用。这容易导致依赖关系的复杂和混乱,而且每次都需要重新编译和打包,也很不方便,更不要说对现有的模块进行编排和组合了。将这些模块转变为服务后,我们只需要调用这些服务,而不需要关心服务的具体实现、依赖和提供者。同时还能够使用服务编排工具将现有服务编排到新的流程中,组合成为新的服务,或者修改现有的服务流程。
2. 方便开发和调试
每一个微服务专注于单一功能,并通过定义良好的接口来清晰表述它的边界。服务越小,复杂度越低,开发起来也就越简单、越快,调试和维护也更方便。这就缩短了服务开发和修改的周期,使程序能更快地迭代。
3. 方便部署与更新
微服务一般随应用部署。一个系统中有若干可独立运行的应用,每个应用通常提供了一个或多个微服务。当某个微服务发生变更时,只需编译和部署相应的应用,而不用重新编译和部署整个系统。这使得部署发布更加高效,同时也缩小了每次变更和部署的影响范围,降低了风险。
4. 系统集成更方便
使用不同语言、不同技术栈开发的服务,只要按照统一的协议暴露,比如统一使用HTTP RESTful形式暴露为服务,就可以方便地相互调用和协同。这使得我们能够将各类系统轻松集成在一起。
5. 提高容错能力
某一模块或组件发生故障时,容易导致整个系统变得不可用。比如,某个模块的内存泄漏可能导致整个应用因内存不足而崩溃。由于微服务架构中的服务粒度很小,且相互隔离,因此即使某个服务出现问题,处理起来也相对容易,影响范围有限。微服务系统可以通过失败重试、失败转移、服务降级等机制实现容错处理,避免问题扩大,微服务系统甚至能自动从故障中恢复(自愈)。
6. 方便横向扩展
当某个服务出现性能瓶颈时,我们只需要增加此服务所属应用的部署数量,而不用增加整个系统的部署。而且,由于不同的服务对资源的要求不同,我们可以根据实际情况灵活地对服务进行混合部署,以便更合理地分配服务器资源。
RPC与微服务
微服务环境下服务的粒度更细,调用频率也更高,一般用于系统内部的面向服务架构,而不是直接对外提供服务。在这种场景下,Web Services的跨语言、跨平台优势不再那么重要,Web Services的易用性问题和性能问题反而变得突出起来。
随着Socket、多线程、序列化等技术的发展,涌现出了很多优秀的RPC框架,以代替传统的RMI等技术。与Web Services偏向对外暴露服务与远程调用不同,RPC框架专注于细粒度(方法级别)的、系统内部模块或组件之间的相互调用与协同。由于多数RPC框架采用Socket长连接和二进制协议,因此其性能比基于HTTP协议的Web Services要高几个数量级。再加上,RPC可以做到对应用的零侵入,因此其在易用性方面也要强得多。
由于RPC在易用性和性能方面优势明显,因此在系统内部,使用远程方法调用(RPC)形式暴露和引用服务要比Web Services更合适。对外暴露和引用服务时(跨系统调用)再采用Web Services的形式。当然,如果对性能要求不高,也可以一律采用HTTP RESTful方式。有些RPC框架,如gRPC、Thrift,支持跨语言调用,也可以被用于跨系统的服务调用,对外提供服务。由于我们总是能轻松地将系统内部的服务以Web Services 形式对外暴露,因此,建议优先考虑内部服务调用的性能和易用性,选用RPC作为微服务的核心和基础。
微服务框架
在微服务领域,比较流行的几个关键词是Spring Cloud、Dubbo、Docker、Kubernetes、Service Mesh。其中Spring Cloud是目前最接近完整微服务框架的产品。它是一个基于Java语言的微服务开发框架,面向的是有Spring开发经验的Java语言开发者。但它真的只是一个“框架”性的东西,还需要集成一系列的第三方组件才能发挥作用。Netflix公司为其开发了一套组件,并成为Spring Cloud的推荐或默认实现。
Dubbo是阿里巴巴开源的分布式服务框架。其本质上是一个高性能二进制RPC框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。其功能主要包括高性能NIO通信及多协议集成、服务动态寻址与路由、软负载均衡与容错、依赖分析与服务降级等。可以看出Dubbo有着自己的多层架构体系,涵盖了Spring Cloud中的一部分内容。它虽然算不上一个完整的微服务框架,但却比较实用,未来可能会支持与Spring Cloud的集成,融入Spring Cloud生态圈。
Docker是一个应用容器引擎,允许我们将要部署的应用和运行时环境打包成一个镜像文件,部署到Docker容器中。Rocket 是与之类似的另一款应用容器引擎。
Kubernetes是Google开源的一个自动化容器操作平台,简称K8S。它可以编排并自动执行容器(如Docker、Rocket)的部署、复制等操作,随时扩展或收缩容器规模,并提供容器间的负载均衡,监控容器的状态,自动升级或替换容器。由此可见,Kubernetes不是面向开发者的平台,而是面向IT基础设施运维人员的。
Spring Cloud和Dubbo同属于PaaS(Platform as a Service,平台即服务),而Docker和Kubernetes同属于IaaS(Infrastructure as a Service,基础设施即服务)。由于微服务平台中服务的载体是应用,而环境中要部署的应用实例众多,因此使用Docker和Kubernetes,通过整合Spring Cloud、Docker和Kubernetes,可以构建更加完整和强大的微服务架构程序。
不过,应用的部署并不一定需要Docker这样的容器,Linux自身就支持进程间的资源隔离。通过一个简单应用代理服务(Agent)加Shell脚本即可实现应用的部署。本书所介绍的示例微服务系统正是使用了这一方式,效果也很好。使用这种方式可以实现应用的部署、启停、更新、JVM监控、资源监控等功能,扩展也更方便。
Service Mesh则还是一个比较新的概念。它可将微服务间的调用、限流、熔断和监控等功能需求提炼为一个通用的中间层基础服务,甚至下沉到基础设施层。Spring Cloud、Kubernetes和Istio似乎都正在朝这一方向努力。
本书作为示例所介绍的mac-rpc和Dubbo非常相似,其本质是一个内置服务注册与发现功能的高性能RPC框架,是微服务系统的核心和基础。其特点是全异步和高性能,小巧精练,但开放、灵活,可自由定制和扩展。mac-rpc目前已经较为成熟和稳定,其最新版本是1.0.3。它与服务治理系统、流程引擎、自动化部署、消息、缓存等子系统和组件集成,可以构建起完整的微服务系统。读者若想了解更多关于mac与boar系列的开源项目,请访问http://www.boarsoft.com和https://www.gitee.com/Mac_J/projects。

目录

第1章 多线程基础
1.1 多线程的概念
1.1.1 进程与线程
1.1.2 并发与并行
1.1.3 线程状态
1.2 Thread线程类
1.2.1 基本用法与思考
1.2.2 常用方法介绍
1.2.3 wait和sleep的区别
1.2.4 sleep和yield的区别
1.3 Runnable接口
1.4 线程池
1.4.1 Executors
1.4.2 ExecutorService
1.4.3 ThreadPoolExecutor
1.4.4 基本用法与思考
1.5 Callable与Future
1.6 线程安全与效率
1.6.1 什么是线程安全
1.6.2 线程同步
1.6.3 饥饿与公平
1.6.4 锁与死锁
1.6.5 线程中断
1.7 编程进阶
1.7.1 volatile关键字
1.7.2 synchronized关键字
1.7.3 wait/notify/notifyAll
1.7.4 CAS操作
1.7.5 atomic包
1.7.6 Lock自旋锁
1.7.7 Condition条件变量
1.7.8 线程安全容器
1.7.9 ThreadLocal类
1.7.10 CountDownLatch计数器
1.7.11 CyclicBarrier栅栏
1.7.12 Semaphore信号量
1.7.13 fork/join框架
第2章 Socket基础
2.1 TCP与Socket
2.2 TCP的通信过程
2.2.1 基本过程
2.2.2 建立连接
2.2.3 全双工异步通信
2.2.4 断开连接
2.2.5 优雅地断开
2.2.6 半……连接
2.3 通信方式
2.3.1 长连接与短连接
2.3.2 线程模型
2.3.3 拆包与组包
2.3.4 断包与粘包
2.3.5 数据包的结构
2.4 BIO
2.4.1 典型编程模型
2.4.2 关键API概述
2.4.3 字符流传输
2.4.4 字节流传输
2.4.5 传输多笔数据
2.5 NIO
2.5.1 NIO简介
2.5.2 Buffer
2.5.3 Channel
2.5.4 Selector
2.5.5 Scatter/Gather
2.5.6 Pipe
2.5.7 内存映像文件
2.5.8 文件传输示例
2.5.9 “聊天室”示例
2.6 AIO
2.6.1 AIO简介
2.6.2 关键API概述
2.6.3 示例代码
第3章 Spring与Spring Cloud
3.1 Spring简介
3.2 IoC容器
3.2.1 IoC的概念
3.2.2 Spring中的bean
3.2.3 XML配置方式
3.2.4 注解配置方式
3.2.5 用Java类来配置
3.2.6 BeanFactory与FactoryBean
3.2.7 ApplicationContext与ApplicationContextAware
3.2.8 动态注册bean配置
3.2.9 ApplicationListener与容器事件
3.3 bean的基本配置
3.3.1 scope属性
3.3.2 parent与abstract
3.3.3 factory-bean与factory-method
3.3.4 bean的初始化与释放
3.4 依赖注入
3.4.1 setter注入
3.4.2 工厂方式注入
3.4.3 构造器注入
3.4.4 注解注入
3.5 Spring Boot
3.5.1 快速创建工程
3.5.2 编码与测试
3.5.3 打包部署
3.5.4 辅助开发工具
3.5.5 监控功能
3.6 Spring Cloud
3.6.1 Spring Cloud简介
3.6.2 架构设计
3.6.3 创建应用
3.6.4 服务的注册与发现
3.6.5 服务配置
3.6.6 Ribbon负载均衡
3.6.7 Feign服务调用
3.6.8 Hystrix
3.6.9 Zuul服务路由
3.6.10 服务监控
第4章 动态代理
4.1 代理模式
4.2 静态代理
4.3 类的装载
4.4 Java反射
4.5 JDK动态代理
4.6 CGLIB动态代理
4.7 Java Compiler API
4.8 Javassist动态代理
第5章 对象序列化
5.1 什么是序列化
5.2 Java序列化
5.2.1 基本用法
5.2.2 关于serialVersionUID
5.2.3 自定义序列化
5.2.4 封装实现代码
5.3 Hessian序列化
5.4 Kryo序列化
5.5 FST序列化
5.6 其他序列化组件
5.7 集成与扩展
5.7.1 优雅地集成
5.7.2 使用Java SPI
5.7.3 使用Spring
第6章 框架设计
6.1 总体结构
6.1.1 逻辑架构
6.1.2 框架设计概述
6.1.3 RPC原理
6.1.4 工程结构
6.1.5 依赖的jar包
6.1.6 主要的类
6.2 初始化过程
6.2.1 Spring配置
6.2.2 应用节点的启动
6.2.3 Web容器的启动
6.2.4 RpcCore的初始化
6.2.5 RpcContext的初始化
6.3 服务的暴露
6.3.1 服务暴露配置
6.3.2 方法配置与ID
6.3.3 内置的服务方法
6.3.4 服务提供方本地调用器
6.3.5 服务提供方代理生成器
6.3.6 注册要暴露的服务
6.4 服务的引用
6.4.1 服务引用配置
6.4.2 本地引用工厂类
6.4.3 注册本地引用工厂
6.4.4 本地引用与方法ID
6.5 服务的注册与发现
6.5.1 注册表集合
6.5.2 注册表的同步
6.5.3 注册表的解析
6.5.4 提交注册表
6.5.5 注册表推送
6.5.6 注册表检查
6.6 优雅地停机
6.6.1 停机的过程
6.6.2 停机钩子
6.6.3 监听Web容器的关闭
6.6.4 RpcCore的关闭
6.6.5 停机通知的处理
第7章 方法调用
7.1 方法调用类型
7.2 同步调用
7.2.1 同步调用的时序
7.2.2 同步调用的发起
7.2.3 负载均衡
7.2.4 指定服务提供者
7.2.5 失败转移
7.2.6 发送调用请求
7.2.7 处理调用请求
7.2.8 处理调用响应
7.3 异步调用
7.3.1 异步调用的时序
7.3.2 异步调用的发起
7.3.3 异步调用的执行
7.3.4 方法调用对象
7.4 同步/异步通知
7.5 异步回调
7.6 广播调用与广播通知
7.6.1 广播示例
7.6.2 广播代码
第8章 通信层实现
8.1 Socket通信框架
8.1.1 Netty与Mina
8.1.2 为什么要自己写
8.1.3 是NIO还是AIO
8.1.4 设计思路
8.1.5 实际结构
8.2 通信协议
8.2.1 传输对象
8.2.2 数据包结构
8.2.3 拆包与发送
8.2.4 接收并组包
8.3 连接的建立
8.3.1 工作模型
8.3.2 开始监听
8.3.3 发起连接
8.3.4 绑定连接
8.3.5 断线检测
第9章 性能测试与调优
9.1 性能调优概述
9.1.1 性能指标
9.1.2 性能瓶颈
9.1.3 环境因素
9.2 压力测试
9.2.1 测试方法
9.2.2 场景设计
9.2.3 测试环境
9.2.4 Dubbo配置
9.2.5 测试程序
9.3 线程池调优
9.3.1 调整线程池的大小
9.3.2 选择合适的队列
9.3.3 线程的管理逻辑
9.3.4 选择拒绝策略
9.4 优化线程同步
9.4.1 减少上下文切换
9.4.2 避免线程滥用
9.4.3 避免过多的锁
9.4.4 synchronized VS Lock
9.4.5 缩小锁的范围和粒度
9.4.6 线程分析工具
9.5 JVM调优
9.5.1 堆与栈
9.5.2 JVM内存的分代
9.5.3 GC分类
9.5.4 GC算法
9.5.5 分代GC
9.5.6 对象的引用
9.5.7 内存大小设置
9.5.8 内存调优工具
9.6 其他优化内容
9.6.1 避免使用反射
9.6.2 对象池
9.6.3 缓冲区队列
9.6.4 使用直接内存
9.6.5 缓存其他对象
9.6.6 协调与平衡
第10章 服务治理
10.1 服务治理概述
10.1.1 什么是服务治理
10.1.2 服务治理架构
10.1.3 服务治理接口
10.2 服务的定义
10.2.1 服务识别
10.2.2 接口定义
10.2.3 版本管理
10.2.4 协议适配
10.2.5 服务设计
10.2.6 服务的实现
10.2.7 依赖关系管理
10.3 服务的部署
10.3.1 服务的部署方式
10.3.2 自动化部署
10.3.3 服务的热部署
10.4 注册与发现
10.4.1 WSDL与UDDI
10.4.2 ZooKeeper的方案
10.4.3 Eureka的方案
10.4.4 Consul的方案
10.4.5 etcd的方案
10.4.6 注册中心集成方案
10.5 服务的控制
10.5.1 服务状态
10.5.2 服务控制
10.5.3 服务开关
10.5.4 服务模拟
10.5.5 黑白名单
10.5.6 “踢除”服务提供者
10.6 监控与限流
10.6.1 TPS监控与限流
10.6.2 响应时间的监控
10.6.3 调用链的监控
10.6.4 资源监控


本书勘误

印次
  • 页码:11  •  行数:1.6.1章节的C1_6_1构造函数  •  印次: 1

    构造函数写成了C1_9_1

    HustGenji 提交于 2019/8/21 11:35:09
    陈晓猛 确认于 2019/8/21 15:59:09
  • 页码:62  •  行数:3  •  印次: 1

    客户端在发送完成之后不可能通过 shutdownOutput 来告知服务端我的数据已经发送完成。shutdownOutput 的作用为了禁止 socket 持有方再次发送数据,并不能起到通知接收方数据已经发送完成的功能。socket 持有方在调用 shutdownOutput 之后如果想要再次发送数据只能建立新的 socket 连接。

    伯纳罗 提交于 2021/10/28 21:52:39
    陈晓猛 确认于 2021/11/10 16:17:00
  • 页码:78  •  行数:文件传输实例  •  印次: 1

    本书的文件传输示例,p78页是错误的。

    因为服务端采用的是NIO模型,在处理就绪的读事件时,只是读取了当前socket的读缓冲区,若客户端发送的文件很大时,其实这里只是读了一部分文件。书中代码在从channel读完数据时,直接注册写事件发ok是不对的。因为这时服务端在一次select时可能没有读取全部文件数据,之后的写事件处理发ok,然后关闭socket。客户端由于数据没发完,还会继续发送文件数据,但此时对端已经关闭socket,就会出错。 不信,你可以运行代码读取一个1G的文件试试。正常的做法,还是发送文件前,告诉服务端这次文件的大小,服务端只有在读到给定长度的字节后,才注册写事件,向客户端发ok。

    修正后的代码仓库为:https://github.com/SpecialYy/NIO-File-Transfer

    SpecialYang 提交于 2019/6/9 12:26:08
    陈晓猛 确认于 2019/6/12 6:39:21

读者评论

  • 资源情况说明
    第一、没有示例代码就没有,为什么陈晓猛(应该是出版社编辑之类的)评论区还一直在强调仔细阅读本书还把前言中不相关的地址贴出来,这么多读者都是傻子吗?大家看这本书好歹是了解计算机知识的人吧,难道连下载资源都不会?

    第二、我以为看书不仅是书中的资源更加直观系统,比视频教学来的更加迅速,还能更好的做笔记等但是学习也是需要花费时间的,能尽量的节省时间也是非常必要的,我们拿到示例代码后,分析各种情况并适当修改后执行并且观察其输出情况也是非常有必要的,大家也都不是初学者都懂的复制粘贴,因为这样效率最高,实践是最快速掌握知识的途径,如果我们还在重复的造轮子这个不是适合时代的发展方式了。

    第三、整个下载资源也就是只有一个pdf。

    伯纳罗发表于 2021/10/13 14:15:40
  • “读者若想了解更多关于mac与boar系列的开源项目,请访问http://www.boarsoft.com和https://www.gitee.com/Mac_J/projects。”我们想要代码示例

    伯纳罗发表于 2021/10/12 13:00:14
  • 前言第八页确实有https://gitee.com/Mac_J/projects 这个地址但是人家说的是如果想了解 mac 和 boar 这个项目再去浏览,这个和书中的示例关系不大,或者说没有示例。另外最下方标明了下载地址中包含了示例文件和资源文件,但是实际只有一个pdf,以后买书前还得看下评论再决定。

    伯纳罗发表于 2021/10/12 12:57:18
  • 我觉得在论坛里面一个个的收集知识都比这本书好,我觉得这本书是我看过最烂的j**a书 知识排版有问题 全部都是浅谈

    冯旭发表于 2020/6/8 2:11:37
    • 我为了不让同学们看这样的书 决定注册评论一下

      冯旭发表于 2020/6/8 2:12:31
  • 能投诉么,没有代码搞个鬼的读者服务

    shiyingdong发表于 2020/6/5 16:12:22