精华内容
下载资源
问答
  • 1、安装的客户端什么意思,安装好以后,再配置一下就可以访问公司的数据库吗?本地客户端只是一个界面? 2、安装的客户端查询的数据什么的,账户和密码是已经建好的,是不是可以自己插数据到公司的数据库呢? 3、...

    疑问:

    最近经常用到oracle数据库,有几点不是很明白。
    1、安装的客户端是什么意思,安装好以后,再配置一下就可以访问公司的数据库吗?本地客户端只是一个界面?
    2、安装的客户端查询的数据什么的,账户和密码是已经建好的,是不是可以自己插数据到公司的数据库呢?
    3、本地安装一个客户端和在本地装一个数据库有什么区别,包括电脑内存等等。

    回答:

    1. 客户端就类似于浏览器,而数据库服务器和web服务器差不多也是类似的比喻。数据都是放在服务器端的,客户端只是负责展示特定的数copy据给用户看,也收集用户的数据,客户端还有一个作用,就是代百理,其他程序,比如JDBC或者其他程序可以通过客户端这个通道,或者桥梁,把数据传递给服务器,以及从服务器获取数据,给需要的程序。

    2. 是的,只要有帐号和密码(还要权限,但初学者可以认为有帐号密码就有权限了),就可以往服务器上查询数据,以及修改数据。

    3. 本地如果只安装客户端,那么考虑一种情况,就是没有网络,则什么操作都执行不了。度而在本地装一个数据库,其实就是在本地安装一个服务器软件。和你们公司的数据库服务器没有本质的区别,其他机器也可以连问到你的笔记本里面的数据库服务器。顺带的,安装本地服务器的时候,会附加的安装一个答客户端,所以本地数据库=服务器+客户端软件

    4. 服务器就是一个存数据的地方,你可以理解为就管理着一些文件,类似于Excel这样的,只是性能更好,更专业。

    展开全文
  • 客户端架构

    万次阅读 2016-05-29 10:56:36
    Blog2-客户端架构 一.客户端架构简介  客户端(Client)或称为用户端,是指与服务器相对应,为客户提供本地服务的程序。除了一些只在本地运行的应用程序之外,一般安装在普通的客户机上,需要与服务端互相配合...

    Blog2-客户端架构

    一.客户端架构简介

       客户端(Client)或称为用户端,是指与服务器相对应,为客户提供本地服务的程序。除了一些只在本地运行的应用程序之外,一般安装在普通的客户机上,需要与服务端互相配合运行。

    架构,又名软件架构,是有关软件整体结构与组件的抽象描述,用于指导大型软件系统各个方面的设计。软件架构是一系列相关的抽象模式,用于指导大型软件系统各个方面的设计。软件架构是一个系统的草图。软件架构描述的对象是直接构成系统的抽象组件。各个组件之间的连接则明确和相对细致地描述组件之间的通讯。在实现阶段,这些抽象组件被细化为实际的组件,比如具体某个类或者对象。在面向对象领域中,组件之间的连接通常用接口(计算机科学)来实现。

    在“软件构架简介”中,David Garlan 和 Mary Shaw 认为软件构架是有关如下问题的设计层次:“在计算的算法和数据结构之外,设计并确定系统整体结构成为了新的问题。结构问题包括总体组织结构和全局控制结构;通信、同步和数据访问的协议;设计元素的功能分配;物理分布;设计元素的组成;定标与性能;备选设计的选择。”

    二.常见的架构方式

    针对数据流动的方向而言,分为分层架构,MVC架构,MVVM架构,MVP架构。

    1.分层

    分层架构是一种常见的软件应用架构,在 Java 程序中可以算是一种应用标准了,通常又叫 N 层架构。

    优点:

    1、开发人员可以只关注整个结构中的其中某一层;

    2、可以很容易的用新的实现来替换原有层次的实现;

    3、可以降低层与层之间的依赖;

    4、有利于标准化;

    5、利于各层逻辑的复用。

    缺点:

    1、降低了系统的性能。这是不言而喻的。如果不采用分层式结构,很多业务可以直接造访数据库,以此获取相应的数据,如今却必须通过中间层来完成。

    2、有时会导致级联的修改。这种修改尤其体现在自上而下的方向。如果在表示层中需要增加一个功能,为保证其设计符合分层式结构,可能需要在相应的业务逻辑层和数据访问层中都增加相应的代码。

    1.1三层架构

    最常见的是 3 层架构,它从上至下包含如下 3 层:

    展示层(Presentation tier),也称为 UI 层,也就是程序的界面部分。

    业务层(business logic(domain) tier), 业务层,是最为核心的一层。

    持久层(Data tier),数据持久层。

    层次

    作用

    设计原则

    表示层(UI)

    向用户展现特定业务数据,采集用户的输入信息和操作。

    用户至上,兼顾简洁;不包含任何业务相关的逻辑处理。

    业务逻辑层(BLL)

    从DAL中获取数据, 在UI显示; 从UI中获取用户指令和数据, 执行业务逻辑或通过DAL写入数据源。

    作为U层与D层的桥梁,目的在于展现清晰的函数结构, 只负责数据处理传递, 不涉及SQL语句和ADO.NET。

    数据访问层(DAL)

    直接操作数据库,针对数据的增添 删除 修改 查找; 具体为业务逻辑层或表示层提供数据服务。

    专门操作数据库, 不考虑数据合法性. 数据库错误返回-1, 逻辑错误返回0, 并告知错误原因, 成功返回1

     

    3 层架构是存在物理上分层概念的,从上往下即展示层、业务层、持久层,也从上往下由上一层依赖下一层。不同层之间也是高内聚低耦合的体现,层内高内聚,层间低耦合,层是层内具体工作的高度抽象。低耦合则是依赖倒转原则体现出来,高层依赖于下层的抽象而不是具体。

    1.2四层架构

    在三层架构的基础上多了业务规则层,通常的三层是把业务逻辑和业务规则合并为一个层,统称为业务层.业务规则层的提出,既可以及时处理用户输入的不合法信息, 又可以及时处理数据库错误, 增大了业务逻辑层的结构清晰度, 让业务逻辑人员专心致志做逻辑。

    从上至下为:

    l  表示层

    l  业务规则层

    l  业务逻辑层或称为领域层

    l  数据访问层

    层次

    作用

    设计原则

    业务规则层(ECL)        

    对于UI层传下来的参数来说,检查合法性。

    用户至上,兼顾简洁;不包含任何业务相关的逻辑处理。

    1.3引入service层

    引入service层的架构和普通的分层架构的不同是: service层内部有数据, 可以单独运行。

    从上至下为

    l  表现层

    l  服务层(service)

    l  数据访问层

    l  业务逻辑层

    层次

    作用

    表现层    

    显示与用户的交互。

    服务层

    service层提供表现层的业务逻辑入口,通过定义接口服务的形式,通过接口调用来完成。

    业务逻辑层

    1接收服务层传来的DTO, 然后根据业务规则, 对传入的DTO进行加工, 返回加工后的信息

    2 需要为每个对象提供业务行为, 并且这些对象之间是独立的

    3 业务对象之间的交互流程通过服务层来组织

    数据访问层

    本地数据远程数据的访问接口。

     

    2.MVC

    MVC指Model-View-Controller。

    层次

    作用

    设计原则

    M(模型层)

    封装了应用的一系列数据, 并定义了操作, 处理这些数据的逻辑和计算规则。

    通过Notification,KVO对控制器进行反馈

    V(视图层)

    视图对象是一个应用中, 用户可以看到的对象. 视图对象知道如何绘制自己, 也能够响应用户的操作. 视图对象的主要目的之一是将应用模型对象中的数据显示出来, 并允许用户编辑该数据。

    视图通过不能直接操作模型层, 通过target-action, delegate, dataSource和控制器进行反馈

    C(控制器层)

    控制器层是在视图层和若干个模型层的中间人

    c可以直接操作模型层和视图层

     

    下图说明了MVC之间的交互。

    优点:

    (1) 可以为一个模型在运行时同时建立和使用多个视图。变化-传播机制可以确保所有相关的视图及时得到模型数据变化,从而使所有关联的视图和控制器做到行为同步。

    (2) 视图与控制器的可接插性,允许更换视图和控制器对象,而且可以根据需求动态的打开或关闭、甚至在运行期间进行对象替换。

    (3) 模型的可移植性。因为模型是独立于视图的,所以可以把一个模型独立地移植到新的平台工作。需要做的只是在新平台上对视图和控制器进行新的修改。

    (4) 潜在的框架结构。可以基于此模型建立应用程序框架,不仅仅是用在设计界面的设计中。

    缺点:

    (1) 增加了系统结构和实现的复杂性。对于简单的界面,严格遵循MVC,使模型、视图与控制器分离,会增加结构的复杂性,并可能产生过多的更新操作,降低运行效率。

    (2) 视图与控制器间的过于紧密的连接。视图与控制器是相互分离,但确实联系紧密的部件,视图没有控制器的存在,其应用是很有限的,反之亦然,这样就妨碍了他们的独立重用。

    (3) 视图对模型数据的低效率访问。依据模型操作接口的不同,视图可能需要多次调用才能获得足够的显示数据。对未变化数据的不必要的频繁访问,也将损害操作性能。

    (4) 目前,一般高级的界面工具或构造器不支持MVC模式。改造这些工具以适应MVC需要和建立分离的部件的代价是很高的,从而造成使用MVC的困难。

    1.1安卓客户端的MVC

    V:V在MVC架构中Activity(托管Fragment,View,WebView等)首先充当V的角色。

    M:业务逻辑层划分出来专门处理数据。例如:数据的http请求,数据解析和储存等逻辑都封装在这一层。Activity 不直接和Http,Dao(数据访问对象层)直接有联系了,视图数据从此为路人。

    C:接受或控制事件或逻辑层的回调响应。

    1.2Java Swing的MVC

    Swing是一个标准的MVC结构

    • ComponentUI代表View,负责描画组件。

    • 组件由其Model层,比如JTextField的Document,JTable的TableModel, JTree?的TreeModel等等。

    • 而Controller可能不是很明显,我们或许可以简单的将其Event机制看作一个Swing团队开发给开发者的Controller.

    3.MVVM

    MVVM是在MVC的基础上多了一个View Model: 表示逻辑, 将 model 的数据转换为 view 可以呈现的东西。适合大量展示类的App。

    MVVM指Model-View-ViewModel,是一个从 MVC 模式中进化而来的设计模式。

    Model,domain model(领域模型)或是数据层代表的数据模型,也可以理解为用户界面需要显示数据的抽象(数据)。

    View, 应用的界面

    ViewModel,binder 所在之处,是 View 的抽象,对外暴露出公共属性和命令,是 View 与 Model 的(绑定)连接器。

    下图是一组MVC,MVP和MVVM的对比图片。

    最早于2005年被微软的 WPF 和 Silverlight 的架构师 JohnGossman 提出。

    举例来说,在 iOS 开发中实践 MVVM 的话,通常会把大量原来放在 ViewController 里的视图逻辑和数据逻辑移到ViewModel 里,从而有效的减轻了ViewController 的负担。另外通过分离出来的 ViewModel 获得了更好的测试性,我们可以针对 ViewModel 来测试,解决了界面元素难于测试的问题。MVVM 通常还会和一个强大的绑定机制一同工作,一旦ViewModel 所对应的 Model 发生变化时,ViewModel 的属性也会发生变化,而相对应的View 也随即产生变化。

    优点:

    (1)低耦合。视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的View上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。

    (2)可重用性。你可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。

    (3)独立开发。开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计,使用Expression Blend可以很容易设计界面并生成xml代码。

    (4)可测试。界面素来是比较难于测试的,而现在测试可以针对ViewModel来写。

    缺点:

    一个首要的缺点是,MVVM 的学习成本和开发成本都很高。MVVM 是一个年轻的设计模式,大多数人对他的了解都不如 MVC 熟悉,基于绑定机制来进行编程需要一定的学习才能较好的上手。同时在客户端开发中,并没有现成的绑定机制可以使用,要么使用 KVO,要么引入类似 ReactiveCocoa 这样的第三方库,使得学习成本和开发成本进一步提高。

    另一个缺点是,数据绑定使 Debug 变得更难了。数据绑定使程序异常能快速的传递到其他位置,在界面上发现的 Bug 有可能是由 ViewModel 造成的,也有可能是由 Model 层造成的。传递链越长,对 Bug的定位就越困难。

    同时还必须指出的是,在传统的 MVVM 架构中,ViewModel 依然承载的大量的逻辑,包括业务逻辑,界面逻辑,数据存储和网络相关的逻辑,使得 ViewModel 仍然有可能变得和 MVC 中 ViewController 一样臃肿。

    3.1安卓客户端的MVVM

    目前 Android 的 data binding 还是 beta,还只是 one-way 单向绑定,功能上还有所欠缺、控制性也还不强,但是把它写出来还是没问题的。对于 Activity、Fragment 而言仅仅是作为 Java View 看待,与 XML 对应,所以里面只有 View 的展现逻辑,此外没有其它代码。一个Activity 或 Fragment(一般都 with XML) 对应一个 ViewModel,对于一个基础 View(XML)可以通过继承对应的 ViewModel 实现重用,本文的代码也有体现。对于 Activity 和 Fragment 的View 状态保存恢复也通过 ViewModel 处理。因为 binding 的入口在 Activity 或 Fragment 中,所以为了方便写个基类处理ViewModel 和 Binding 的初始化,然后在对应的 XML 里加上 ViewModel 的 variable, XML 里不再有其它数据对象的 variable。

    ViewModel 中通过ObservableField 来达到细粒度的控制,绑定操作都放在ViewModel 里,然后 ViewModel 里可以有多个 domain 中的Interator(UseCase) 来得到 View 需要渲染的数据 Model。对于 ObservableField 的绑定操作和命令操作(Command)都是暴露的,也易于测试。binding现在缺少手动在 Java 代码中注册通知事件的功能,比如有些 model 的渲染必须通过 Java 代码来操作的话就需要了,在 Activity(Java View)中通过向 Binding 注册通知回调,而目前只能在 XML 中知道,当然目前也可以自己实现,方法也有多种:接口回调、EventBus、RxBus。

    下图是MVVM的架构图。

    4.MVP

    Model-view-presenter (MVP) 是使用者界面设计模式的一种,被广范用于便捷自动化单元测试和在呈现逻辑中改良分离关注点(separation of concerns)。

    Model定义使用者界面所需要被显示的资料模型,一个模型包含着相关的业务逻辑。View视图为呈现使用者界面的终端,用以表现来自Model 的资料,和使用者命令路由再经过Presenter对事件处理后的资料。Presenter包含着元件的事件处理,负责检索Model取得资料,和将取得的资料经过格式转换与View进行沟通。

    优点:

    (1)模型与视图完全分离,我们可以修改视图而不影响模型。

    (2)可以更高效地使用模型,因为所有的交互都发生在一个地方----Presenter内部。

    (3)我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型的变化频繁。

    (4)如果我们把逻辑放在Presenter中,那么我们就可以脱离用户接口来测试这些逻辑

    缺点:

    由于对视图的渲染放在了Presenter中,所以视图和Presenter的交互会过于频繁。还有一点需要明白,如果Presenter过多地渲染了视图,往往会使得它与特定的视图的联系过于紧密。一旦视图需要变更,那么Presenter也需要变更了。比如说,原本用来呈现Html的Presenter现在也需要用于呈现Pdf了,那么视图很有可能也需要变更,可修改性下降。

    4.1安卓客户端的MVP

    很多时候视图层面还是充斥中很多复杂的逻辑,例如UI事件的响应处理,网络响应的回调等等,充斥着各种监听器的回调。我们期望视图V便当更简单、更纯粹,V只负责绘制和刷新其他逻辑都不用管了,也不想和M有直接的联系。从MVC的VC(Activity)中我们分离一层出来叫做Presenter,由它来负责调度UI何时刷新、由它来接受UI的事件响应并传达指令给M。从此V和M是路人,V和数据的距离更远了。

    V:Activity为代表,这时候的Activity更为简单了,只负责UI的绘制和刷新。

    P:负责传达指令。向上接收V的事件指令并需要的时候传达给M,向下接收M的指令并通知V刷新UI。

    M:只负责出来数据逻辑。其实还可以细分一些东西,比如Http请求,很多时候Http框架都是用的第三方开源框架,如果有一天更优秀的框架出现了,要更换,怎么才能做到不影响其他层次?如果做了分层隔离那么,可以很轻松的换掉,如果没有做分层隔离,那么可能要在每一个功能模块的M中修改代码,修改代价是巨大的,所以一般第三方开源框架都不会直接使用而是在业务上做一层抽象隔离。同理,本地数据的存储,也有必要做响应的封装或隔离,可能今天是用Litepal,也许某一天想用GreenDao了,只需要修改封装类的代码就好了。

    MVP的依赖关系:

    MVP类图:

    把每一层都抽象成一个接口,例如V层,我们定义一个接口为View(不要和Android API里的View弄混了),让后Activity为这个View的具体实现。每一层对另一层的依赖都是接口依赖,并不关心另一层的具体实现,每一层我们都可以写不同的实现,随时切换,这就意味着,有一天如果有一层不好用了,可以轻松的重写另一个实现来替换掉,而不是如履薄冰的修改。

    5. HMVC

    Hierarchical MVC, 把客户端应用程序分解为有层次的父子关系的MVC, 反复应用这个模式, 形成结构化的客户端架构. 适合重型B/S架构的WebApp。

    一个MVC模块由应用程序的一个模块抽象而成. 其中很重要的一个概念就是 Parent MVC , 它可以对应界面上的实体, 也可以是一个抽象的对象. 设想一个app 有标签栏, 工具栏, 导航栏, 主工作区, 对应到HMVC上就是这个app最底部的标签栏是 Layer1, Layer2 导航栏,主要工作区, 工具栏. 如果觉得 Layer2 太复杂可以吧主要工作区放到 Layer3, 依次类推.

    Controller 是功能模块的总控室, 它负责和子Controller或父Controller通信,并通知它的 View 处理改变界面显示, Model 处理一些业务逻辑或数据库访问操作. 如刚才的例子里, 点击了工具栏里的一个按钮, 工具栏的Controller 响应这个event, 发现是要切换主工作区, 工具栏做不了,就传递他的父Controller处理(如果父Controller也处理不了, 就继续往上传递)然后标签栏的Controller处理切换主工作区.

    优点:

    (1)把程序分成了几个部分, 降低了依赖性

    (2)支持鼓励重用代码, 组件或者模块。

    (3)在今后的维护中, 提高了可扩展性。

    缺点:

    不利个案创作、独立创作、难艺术化、难个性化。

    6. VIPER

    VIPER,通过把APP架构划分为线框、视图、展示、交互、实体、数据六个层次,使得开发工作可以在最早的时候就参与进来,并且完全可以开发出后面无须改变的整体架构代码。

    使用VIPER架构,可以在AppDelegate里通过唯一的一个实例对象管理整个APP的依赖,并且非常直观地管理整个APP的实例对象关系。

    通过视图、事件、交互三组协议的协议对象,使得视图显示、事件处理、交互数据这三块的类可以得到彻底分离。未来面对APP功能修改或增加时,将会变得非常容易,代码变化被约束到了最小的范围。

     

    三.如何评估架构

    正如同软件本身有其要达到的目标,软件架构设计要达到如下的目标:

    1.可靠性(Reliable)。软件系统对于用户的商业经营和管理来说极为重要,因此软件系统必须非常可靠。

    2.安全性(Secure)。软件系统所承担的交易的商业价值极高,系统的安全性非常重要。

    3.可扩展性(Scalable)。软件必须能够在用户的使用率、用户的数目增加很快的情况下,保持合理的性能。只有这样,才能适应用户的市场扩展的可能性。

    4.可定制化(Customizable)。同样的一套软件,可以根据客户群的不同和市场需求的变化进行调整。

    5.可伸缩 (Extensible)。在新技术出现的时候,一个软件系统应当允许导入新技术,从而对现有系统进行功能和性能的扩展。

    6.可维护性(Maintainable)。软件系统的维护包括两方面,一是排除现有的错误,二是将新的软件需求反映到现有系统中去。一个易于维护的系统可以有效地降低技术支持的花费。

    7.客户体验(Customer Experience)。软件系统必须易于使用。

    8.市场时机(Time to Market)。软件用户要面临同业竞争,软件提供商也要面临同业竞争。以最快的速度争夺市场先机非常重要。

    四.框架

    1. volley

    特点:

    (1) JSON,图像等的异步下载;

    (2) 网络请求的排序(scheduling)

    (3) 网络请求的优先级处理

    (4) 缓存

    (5) 多级别取消请求

    (6) 和Activity和生命周期的联动(Activity结束时同时取消所有网络请求)

    2. android-async-http

    特点:

    (1) 在匿名回调中处理请求结果

    (2) 在UI线程外进行http请求

    (3) 文件断点上传

    (4) 智能重试

    (5) 默认gzip压缩

    (6) 支持解析成Json格式

    (7) 可将Cookies持久化到SharedPreferences

    3. Afinal

    主要有四大模块:

    (1) 数据库模块:android中的orm框架,使用了线程池对sqlite进行操作。

    (2) 注解模块:android中的ioc框架,完全注解方式就可以进行UI绑定和事件绑定。无需findViewById和setClickListener等。

    (3) 网络模块:通过httpclient进行封装http数据请求,支持ajax方式加载,支持下载、上传文件功能。

    (4) 图片缓存模块:通过FinalBitmap,imageview加载bitmap的时候无需考虑bitmap加载过程中出现的oom和android容器快速滑动时候出现的图片错位等现象。

    FinalBitmap可以配置线程加载线程数量,缓存大小,缓存路径,加载显示动画等。FinalBitmap的内存管理使用lru算法,

    没有使用弱引用(android2.3以后google已经不建议使用弱引用,android2.3后强行回收软引用和弱引用,详情查看android官方文档),更好的管理bitmap内存。

    FinalBitmap可以自定义下载器,用来扩展其他协议显示网络图片,比如ftp等。同时可以自定义bitmap显示器,

    在imageview显示图片的时候播放动画等(默认是渐变动画显示)。

    4.xUtils框架

    主要有四大模块:

    (1) 数据库模块:android中的orm框架,一行代码就可以进行增删改查;

    l  支持事务,默认关闭;

    l  可通过注解自定义表名,列名,外键,唯一性约束,NOT NULL约束,CHECK约束等(需要混淆的时候请注解表名和列名);

    l  支持绑定外键,保存实体时外键关联实体自动保存或更新;

    l  自动加载外键关联实体,支持延时加载;

    l  支持链式表达查询,更直观的查询语义

    (2) 注解模块:android中的ioc框架,完全注解方式就可以进行UI,资源和事件绑定;

    l  新的事件绑定方式,使用混淆工具混淆后仍可正常工作;

    l  目前支持常用的20种事件绑定,参见ViewCommonEventListener类和包com.lidroid.xutils.view.annotation.event。

    (3) 网络模块:支持同步,异步方式的请求;

    l  支持大文件上传,上传大文件不会oom;

    l  支持GET,POST,PUT,MOVE,COPY,DELETE,HEAD,OPTIONS,TRACE,CONNECT请求;

    l  下载支持301/302重定向,支持设置是否根据Content-Disposition重命名下载的文件;

    l  返回文本内容的请求(默认只启用了GET请求)支持缓存,可设置默认过期时间和针对当前请求的过期时间。

    (4) 图片缓存模块:加载bitmap的时候无需考虑bitmap加载过程中出现的oom和android容器快速滑动时候出现的图片错位等现象;

    l  支持加载网络图片和本地图片;

    l  内存管理使用lru算法,更好的管理bitmap内存;

    l  可配置线程加载线程数量,缓存大小,缓存路径,加载显示动画等…

    5.ThinkAndroid

    主要有以下模块:

    (1) MVC模块:实现视图与模型的分离。

    (2) ioc模块:android中的ioc模块,完全注解方式就可以进行UI绑定、res中的资源的读取、以及对象的初始化。

    (3) 数据库模块:android中的orm框架,使用了线程池对sqlite进行操作。

    (4) http模块:通过httpclient进行封装http数据请求,支持异步及同步方式加载。

    (5) 缓存模块:通过简单的配置及设计可以很好的实现缓存,对缓存可以随意的配置

    (6) 图片缓存模块:imageview加载图片的时候无需考虑图片加载过程中出现的oom和android容器快速滑动时候出现的图片错位等现象。

    (7) 配置器模块:可以对简易的实现配对配置的操作,目前配置文件可以支持Preference、Properties对配置进行存取。

    (8) 日志打印模块:可以较快的轻易的是实现日志打印,支持日志打印的扩展,目前支持对sdcard写入本地打印、以及控制台打印

    (9) 下载器模块:可以简单的实现多线程下载、后台下载、断点续传、对下载进行控制、如开始、暂停、删除等等。

    (10) 网络状态检测模块:当网络状态改变时,对其进行检测

    6.LoonAndroid

    主要有以下模块:

    (1) 自动注入框架(只需要继承框架内的application既可)

    (2) 图片加载框架(多重缓存,自动回收,最大限度保证内存的安全性)

    (3) 网络请求模块(继承了基本上现在所有的http请求)

    (4) eventbus(集成一个开源的框架)

    (5) 验证框架(集成开源框架)

    (6) json解析(支持解析成集合或者对象)

    (7) 数据库(不知道是哪位写的忘记了)

    (8) 多线程断点下载(自动判断是否支持多线程,判断是否是重定向)

    (9) 自动更新模块

    (10) 一系列工具类

    其中的 volley扩展性非常好,个人比较喜欢的风格。其他如 android-async-http、Afinal 也相当不错。

    7.AndroidAnnotations

    主要有以下特点:

    l  使用依赖注入(DI)、控制反转(IOC)来简化开发过程

    l  简化的线程模型(Simplified threading model)

    l  事件绑定(Event binding)

    l  REST Client

    l  No Magic

    五.非功能指标

    代码整齐,分类明确

    代码整齐是每一个工程师的基本素质。因为代码不仅需要给他人阅读,自己在今后的编程过程中也可能会阅读。如果哪一天架构有修改,正好修改到此处,很容易自己都无法理解。另外,根据“破窗理论”,如果代码不整齐分类不明确,整个架构会随着一次一次的拓展而越来越混乱。

    分类明确的意思是:不要让一个类或者一个模块做两种不同的事情。如果有类或某模块做了两种不同的事情,一方面不适合未来拓展,另一方面也会造成分类困难。

    不用文档,或很少文档,就能让业务方上手。

    业务方由于事务繁忙,很少会留意文档。所以需要尽可能让API的名字可读性强。函数名称长一点没有关系,更重要的是便于理解。

    思路和方法要统一,尽量不要多元。

    解决一个问题会有很多种方案,但是一旦确定了一种方案,就需要在其他地方保持方案的一致性。记录设立某个模块的想法和原因,记录下解决思路,避免之后引入了其他方案,从而导致异构。

    没有横向依赖,万不得已不出现跨层访问。

    跨层访问是指数据流向了跟自己没有对接关系的模块。有的时候跨层访问是不可避免的,比如网络底层里面信号从2G变成了3G变成了4G,这是有可能需要跨层通知到View的。但这种情况不多,一旦出现就要想尽一切办法在本层搞定或者交给上层或者下层搞定,尽量不要出现跨层的情况。跨层访问同样也会增加耦合度,当某一层需要整体替换的时候,牵涉面就会很大。

    对业务方该限制的地方有限制,该灵活的地方要给业务方创造灵活实现的条件。

    架构师必须要有能力区分哪些情况需要限制灵活性,哪些情况需要创造灵活性。比如对于Core Data技术栈来说,ManagedObject理论上是可以出现在任何地方的,那就意味着任何地方都可以修改ManagedObject,这就导致ManagedObjectContext在同步修改的时候把各种不同来源的修改同步进去。这时候就需要限制灵活性,只对外公开一个修改接口,不暴露任何ManagedObject在外面。

    如果是设计一个ABTest相关的API的时候,我们又希望增加它的灵活性。使得业务方不光可以通过Target-Action的模式实现ABtest,也要可以通过Block的方式实现ABTest,要尽可能满足灵活性,减少业务方的使用成本。

    易测试易拓展

    老生常谈,要实现易测试易拓展,那就要提高模块化程度,尽可能减少依赖关系,便于mock。另外,如果是高度模块化的架构,拓展起来将会是一件非常容易的事情。

    保持一定量的超前性

    保持适度的技术上的超前性,能够使得架构更新变得相对轻松。

    另外,超前性不仅仅是技术上的,还有产品上的。了解产品未来走向,就可以在合理的地方为未来留下可拓展的空间。同时,在创业公司的环境下,很多产品需求其实只是为了赶产品进度而产生的妥协方案,最后还是会转到正轨的。这时候业务方可以不实现转到正规的方案,但是架构这边,是一定要为这种可预知的改变做准备的。

    接口少,接口参数少

    越少的接口越少的参数,就能越降低业务方的使用成本。当然,充要条件还是要满足的,需要能够在满足充要条件的情况下尽可能地减少接口和参数数量。

    高性能

    对应每层架构都需要做每层架构的不同优化方案。

     

     

    参考资料:

    1. 《iOS应用架构谈 开篇》

    http://www.cocoachina.com/ios/20150414/11557.html

    2.《ANDROID应用开发架构概述》

    http://www.liuguangli.win/archives/299

    3.架构百度百科

    http://baike.baidu.com/link?url=S0PcGElJ48on43vxXb9d8y3HR3T_kUQ1bRXHAliX4NrFDvVeA-ARyV1T5wRSOSEkvcwhFR9VHuadIPAT_LejwMiswdr1wJGrIWM2oetLwKq

    4.《移动App架构设计》

    http://blog.csdn.net/uxyheaven/article/details/38041091

    5.《值得推荐的android开源框架》

    http://www.ezlippi.com/blog/2014/10/android-opensource.html

     

     

     

    展开全文
  • TortoiseSVN是Subversion版本控制系统的一个免费开源32位客户端,可以超越时间的管理文件和目录。TortoiseSVN文件保存在中央版本库,除了能记住文件和目录的每次修改以外,版本库非常像普通的文件服务器。你可以将...
  • 老师说中间件就像一个网关,可以弄的简单点,但是我平常弄的都是直接在客户端登陆服务器修改服务器的数据,不知道 这个中间件该做什么,该怎么做。我想问下,这个中间件应该怎么弄,大概意思说下就可以。 谢谢。
  •  为了防止本篇日志闲扯太多,我尽量简单说,根据字面意思,socket字面意思是(电源)插座,而套接字本质上是一种网络编程接口,用来完成两个应用程序之间的数据传输。你把设备插头插到电源插座上,设备通上电了,...

    ESP8266_01搭建开发环境

    ESP8266_02程序的编译与下载

    ESP8266_03SDK与Makefile的基本用法

    ESP8266_04管脚控制与软件定时器

    ESP8266_05 ESP8266有几个串口?

    ESP8266_06硬件定时器与IO中断

    ESP8266_07基于PWM的呼吸灯

    ESP8266_08基于flash的数据掉电保护

    ESP8266_09基于IIC控制的OLED屏幕

    ESP8266_10 ESP8266的STATION模式

    ESP8266_11 ESP8266的UDP广播

    ESP8266_12 ESP8266客户端模式下的TCP通信

    ESP8266_13服务器端模式下的TCP通信

    ESP8266_14 SOFTAP模式下的服务器端和客户端

    ESP8266_15天气预报之TCP的GET操作

    ESP8266_16天气预报之JSON数据的生成与解析

    ESP8266_17简单网络时间协议-SNTP

    ESP8266_18 MQTT协议接入ONENET平台

    ESP8266_19MQTT协议接入ONENET平台_订阅主题

    ESP8266_20 基于ONENET平台的数据上传之TCP的POST操作

    ESP8266_21基于ESP8266的一键配网

    ESP8266_22基于自身ADC的电压采样

    ESP8266_23基于硬件定时器的红外遥控器解码

             上一节说了UDP,这一节就聊聊TCP,毕竟它俩经常同时出现。优缺点上一节也提了一下:安全性好,速度慢。

             除了这两点,还有就是:

             TCP通信之前是需要建立连接的,如同打电话之前先拨号一样,而UDP无连接;

             TCP只能一对一通信,UDP不止一对一,还支持一对多;

             TCP对系统资源要求更多,UDP相对少一些。

             所以两者各有优缺点,大家在选择通信协议的时候一定要根据自己的实际情况来确定。

             然后就是客户端,这是啥?和它伴随的,还有一个词经常出现,就是:服务器端。这两者又是什么关系?

             基本上,这两者在TCP通信过程中,都是结伴出现的。以浏览器为例,它就是一个客户端,当我们想上网的时候,输入一个网址。浏览器会根据我们输入的网址向相应的服务器端发出请求,然后服务器端返回相应的网页给浏览器。这就是它们的应用场景之一。

            所以,在TCP通信过程中,一般都是由客户端发起请求,服务器端相应请求。

            那么,在windows/linux下,是如何进行这方面的编程的?步骤如下(参考百度):

    TCP编程的服务器端一般步骤是:

    1、创建一个socket,用函数socket();

    2、设置socket属性,用函数setsockopt(); * 可选

    3、绑定IP地址、端口等信息到socket上,用函数bind();

    4、开启监听,用函数listen();

    5、接收客户端上来的连接,用函数accept();

    6、收发数据,用函数send()和recv(),或者read()和write();

    7、关闭网络连接;

    8、关闭监听;

     

    TCP编程的客户端一般步骤是:

    1、创建一个socket,用函数socket();

    2、设置socket属性,用函数setsockopt();* 可选

    3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选

    4、设置要连接的对方的IP地址和端口等属性;

    5、连接服务器,用函数connect();

    6、收发数据,用函数send()和recv(),或者read()和write();

    7、关闭网络连接;

     

           可以看到,从第四步开始,客户端和服务器端的工作内容有了不一样。

           socket是啥?

           简单来说,是个函数,用来创建套接字。

           那么,套接字又是什么鬼?

           为了防止本篇日志闲扯太多,我尽量简单说,根据字面意思,socket字面意思是(电源)插座,而套接字本质上是一种网络编程接口,用来完成两个应用程序之间的数据传输。你把设备插头插到电源插座上,设备通上电了,同理,你把应用程序的端口插到socket里,数据就通上了。

           注:因为本人是硬件出身,所以对这些协议的理解全靠百度和工作积累,如果有表达错误的,欢迎指正。

           这一节先在8266上面写一个客户端的程序,咱们看一下实现的效果。跟上一节一样,还是要借助一个网络调试助手。同时,本节代码都是在上一节基础上修改来的,所以,如果上一节看懂了,这一节就很好理解,反之,你懂的~

           先说步骤,依然很多,参考上面提到的“TCP编程的客户端一般步骤”,这里大致分为7步:

          1、包含头文件

    #include "espconn.h"
    
    #include "mem.h"

    主要是"espconn.h",涉及到TCP通讯所需的各种数据结构。上一节已经包含了,可以略过。

          2、设置工作模式为station+ soft-ap模式,并连接到当前环境下的wifi

          因为前几步跟上一节一模一样,所以整合了一下:

    wifi_set_opmode(0x03);          // station+ soft-ap模式
    
    struct softap_config config;    //定义AP参数结构体,
    
    wifi_softap_get_config(&config);   //获取当前AP模式的参数
    
    os_memcpy(config.ssid,"ESP8266",strlen("ESP8266"));         //修改AP名称
    
    os_memcpy(config.password,"123456789",strlen("123456789"));      //修改AP密码
    
    config.ssid_len=strlen("ESP8266");         //修改 AP名称的长度
    
    wifi_softap_set_config(&config);             //使修改后的参数生效

    然后连到我家wifi,你们要改成你们家里或者办公室里的wifi。

          3、确定TCP连接的参数

          这里要确定几点:你是谁?你要和谁连接?连接的端口是多少?

          你是谁——ESP8266,8266连接家里路由成功之后,会自动获得一个IP,这是客户端IP

          你要和谁连接——因为是在我电脑上使用网络调试助手模拟TCP服务器端,所以服务器端的IP是我电脑的IP:192.168.1.103

          连接的端口——长话短说,TCP连接的端口从0到65535都有,但一般0~1023是公有的,从1024开始往后,可以选为自己的端口。这里选1024.

    struct ip_info info;
    
    const char remote_ip[4]={192,168,1,103};    //TCP服务端IP
    
    wifi_get_ip_info(STATION_IF,&info);                 //获取8266的WIFI信息
    
    tcp_client_init((struct ip_addr *)remote_ip,&info.ip,1024);

          4、TCP客户端初始化

          其实就是第三步里面的tcp_client_init函数,咱们主要看一下函数内部实现的功能。首先是在client.h文件中定义了一个espconn格式的结构体:

    struct espconn user_tcp_conn;                //对应网络连接的结构体

    然后在tcp_client_init函数中,对结构体的各个部分进行配置:

    {
    
             //TCP通信时,对应的espconn参数配置
    
             user_tcp_conn.type=ESPCONN_TCP;
    
             user_tcp_conn.state=ESPCONN_NONE;
    
             user_tcp_conn.proto.tcp=(esp_tcp *)os_zalloc(sizeof(esp_tcp));
    
             os_memcpy(user_tcp_conn.proto.tcp->local_ip,local_ip,4);
    
             os_memcpy(user_tcp_conn.proto.tcp->remote_ip,remote_ip,4);
    
             user_tcp_conn.proto.tcp->local_port=espconn_port();
    
             user_tcp_conn.proto.tcp->remote_port=remote_port;
    
             //注册连接回调函数和重连回调函数
    
             espconn_regist_connectcb(&user_tcp_conn,user_tcp_connect_cb);
    
             espconn_regist_reconcb(&user_tcp_conn,user_tcp_recon_cb);
    
             //启用连接
    
             espconn_connect(&user_tcp_conn);
    
    }

             函数中可以看到,espconn的参数设置完成之后,注册了两个回调函数,连接完成回调函数(连接完成以后,你想干嘛?)和重连回调函数(重连的时候,该咋办?):

    espconn_regist_connectcb(&user_tcp_conn,user_tcp_connect_cb);
    
    espconn_regist_reconcb(&user_tcp_conn,user_tcp_recon_cb);

             最后,开始TCP连接:

            

    espconn_connect(&user_tcp_conn);      //连接TCP server,连接成功返回0.

     

             5、定义连接成功的回调函数

             void ICACHE_FLASH_ATTR user_tcp_connect_cb(void *arg){
    
             struct espconn *pespconn=arg;
    
             espconn_regist_recvcb(pespconn,user_tcp_recv_cb);
    
              espconn_regist_sentcb(pespconn,user_tcp_sent_cb);
    
              espconn_regist_disconcb(pespconn,user_tcp_discon_cb);
    
              espconn_sent(pespconn,"hello,this is esp8266!",strlen("hello,this is esp8266!"));
    
    }

             函数内部进行了几个操作:

             注册接收完成的回调函数:接收完成以后,你想做点啥~

             注册发送完成的回调函数:发送完成以后,你想做点啥~

             注册断开TCP连接的回调函数:断开TCP连接以后,你想做点啥~

             TCP连接下,发送数据:hello,this is esp8266!

     

             6、定义user_tcp_connect_cb函数内部注册的回调函数

             这里先说一下,基本上从上一节开始,代码的编写就进入了回调函数套回调函数的情形。如果是没接触过回调函数的,刚开始看肯定有些别扭。但如果适应以后,你会发现这样操作还是很方便的。

             因为每个回调函数,在手册里都有说明,功能、参数、返回值,都很清晰。基本上只要看着手册和官方SDK里的例程,大部分问题都能解决。

    //接收完成回调函数,把收到的数据打印出来,延时,断开连接
    
    void ICACHE_FLASH_ATTR user_tcp_recv_cb(void *arg,
    
                       char *pdata,
    
                       unsigned short len){
    
             os_printf("receive data:%s\r\n",pdata);
    
             os_delay_us(300);
    
             espconn_disconnect((struct espconn *)arg);
    
    }
    
    //发送完成回调函数,打印发送完成标志
    
    void ICACHE_FLASH_ATTR user_tcp_sent_cb(void *arg){
    
             os_printf("send success!");
    
    }
    
    //断开TCP连接的回调函数,打印相关信息
    
    void ICACHE_FLASH_ATTR user_tcp_discon_cb(void *arg){
    
             os_printf("disconnect success!");
    
    }

     

             7、定义TCP重连的回调函数

             在第4步里注册了两个回调函数,一个是连接成功的回调函数,第5步已经说了。另一个就是重连的回调函数:

    //如果连接错误,打印一下故障码,然后重新连接
    
             void ICACHE_FLASH_ATTR user_tcp_recon_cb(void *arg, sint8 err){
    
             os_printf("error,error code is%d\r\n",err);
    
             espconn_connect((struct espconn *)arg);
    
    }

          好,到此为止,程序修改完毕。

          注:本例程里提到的大部分函数,都参照手册2c-esp8266_sdk_api_guide_cn_v1.5.4。

          再说一点,很多函数定义的时候,后面会跟一个参数:void *arg,这是什么?

          以第5步里注册回调函数为例:

    espconn_regist_recvcb(pespconn,user_tcp_recv_cb);

          注册了user_tcp_recv_cb函数,这个函数在定义的时候就有如下几个参数

    (void *arg,char *pdata,unsigned short len)

          从哪来的?

          打开手册2c-esp8266_sdk_api_guide_cn_v1.5.4,查找espconn_regist_recvcb函数,可以看到如下说明;

             其中的espconn_recv_callback,咱们继续向下找:

             至此,可以看到相关参数已经在回调函数的格式里定义好了,咱们只需要照着写就行。

     

          程序修改完成,保存、清理、编译、下载一条龙,然后重新上电。这里,需要借助串口助手和网络调试助手两个工具来查看效果。效果如下所示:

             设置网络调试助手:

             可以看到,在网络调试助手上,分别显示了client上线的时间和发来的数据。如果这时候咱们手动给client发一个数据:mcu lover。

             可以在串口助手上看到:

             显示了收到的数据,最后断开TCP连接。

             至此,TCP客户端通信说完了。还是希望大家多动手,毕竟这类东西要动手才有收获。后面会说一下TCP服务器端的用法(跟这个差不多),然后是POST和GET的用法,再然后,就可以根据GET,搞一个天气预报的小应用,相信很多人会比较感兴趣。

             这篇日志写的比较痛苦,因为我是从一个硬件工程师的视角去说这些东西,所以希望跟我类似的人能比较好的理解日志中出现的这些网络协议。因为通常来说,搞硬件的就是搞硬件,画画PCB、搞搞焊接、给单片机写写程序,甚至再写一写上位机,在linux下写一些应用。至于说整天研究TCP/UDP,或者POST、GET,比较少,或者说不算硬件工程师/单片机工程师的范畴了。

             但是物联网芯片的出现打破了这一屏障,它小巧,单片机级别的资源就能应用;但它又强大,可以联网,实现各种网络通信。所以,我们要不停的学习,千万不要自我满足。

    单片机爱好者

     

    展开全文
  • OpenSSH概念和基本用法——SSH 客户端

    千次阅读 2021-01-04 23:59:47
    由于在分布式数据库运维过程中进行脚本自动化必然会涉及SSH登录工具,故摘抄此篇文章以供学习之用。 SSH 是 Linux 系统的登录工具,现在广泛用于服务器登录和各种...SSH 是什么 历史上,网络主机之间的通信是不加密的,

    由于在分布式数据库运维过程中进行脚本自动化必然会涉及SSH登录工具,故摘抄此篇文章以供学习之用。
    SSH 是 Linux 系统的登录工具,现在广泛用于服务器登录和各种加密通信。本教程介绍 SSH(主要是它的实现 OpenSSH)的概念和基本用法,也可以当作手册查询。SSH(Secure Shell 的缩写)是一种网络协议,用于加密两台计算机之间的通信,并且支持各种身份验证机制。它主要用于保证远程登录和远程通信的安全,任何网络服务都可以用这个协议来加密。

    SSH 是什么

    历史上,网络主机之间的通信是不加密的,属于明文通信。这使得通信很不安全,一个典型的例子就是服务器登录。登录远程服务器的时候,需要将用户输入的密码传给服务器,如果这个过程是明文通信,就意味着传递过程中,线路经过的中间计算机都能看到密码,这是很可怕的。
    SSH 就是为了解决这个问题而诞生的,它能够加密计算机之间的通信,保证不被窃听或篡改。它还能对操作者进行认证(authentication)和授权(authorization)。明文的网络协议可以套用在它里面,从而实现加密。

    历史

    1995年,芬兰赫尔辛基工业大学的研究员 Tatu Ylönen 设计了 SSH 协议的第一个版本(现称为 SSH 1),同时写出了第一个实现(称为 SSH1)。当时,他所在的大学网络一直发生密码嗅探攻击,他不得不为服务器设计一个更安全的登录方式。写完以后,他就把这个工具公开了,允许其他人免费使用。
    SSH 可以替换 rlogin、TELNET、FTP 和 rsh 这些不安全的协议,所以大受欢迎,用户快速增长,1995年底已经发展到五十个国家的20,000个用户。SSH 1 协议也变成 IETF 的标准文档。1995年12月,由于客服需求越来越大,Tatu Ylönen 就成立了一家公司 SCS,专门销售和开发 SSH。这个软件的后续版本,逐渐从免费软件变成了专有的商业软件。
    SSH 1 协议存在一些安全漏洞,所以1996年又提出了 SSH 2 协议(或者称为 SSH 2.0)。这个协议与1.0版不兼容,在1997年进行了标准化,1998年推出了软件实现 SSH2。但是,官方的 SSH2 软件是一个专有软件,不能免费使用,而且 SSH1 的有些功能也没有提供。
    1999年,OpenBSD 的开发人员决定写一个 SSH 2 协议的开源实现,这就是 OpenSSH 项目。该项目最初是基于 SSH 1.2.12 版本,那是当时 SSH1 最后一个开源版本。但是,OpenSSH 很快就完全摆脱了原始的官方代码,在许多开发者的参与下,按照自己的路线发展。OpenSSH 随 OpenBSD 2.6 版本一起提供,以后又移植到其他操作系统,成为最流行的 SSH 实现。目前,Linux 的所有发行版几乎都自带 OpenSSH。现在,SSH-2 有多种实现,既有免费的,也有收费的。本书的内容主要是针对 OpenSSH。

    SSH 架构

    SSH 的软件架构是服务器-客户端模式(Server - Client)。在这个架构中,SSH 软件分成两个部分:向服务器发出请求的部分,称为客户端(client),OpenSSH 的实现为 ssh;接收客户端发出的请求的部分,称为服务器(server),OpenSSH 的实现为 sshd。本教程约定,大写的 SSH 表示协议,小写的 ssh 表示客户端软件。另外,OpenSSH 还提供一些辅助工具软件(比如 ssh-keygen 、ssh-agent)和专门的客户端工具(比如 scp 和 sftp),这个教程也会予以介绍。

    SSH 客户端

    简介

    OpenSSH 的客户端是二进制程序 ssh。它在 Linux/Unix 系统的位置是/usr/local/bin/ssh,Windows 系统的位置是\Program Files\OpenSSH\bin\ssh.exe。Linux 系统一般都自带 ssh,如果没有就需要安装。

    # Ubuntu 和 Debian
    $ sudo apt install openssh-client
    # CentOS 和 Fedora
    $ sudo dnf install openssh-clients
    

    安装以后,可以使用-V参数输出版本号,查看一下是否安装成功$ ssh -V

    基本用法

    ssh 最常见的用途就是登录服务器,这要求服务器安装并正在运行 SSH 服务器软件。ssh 登录服务器的命令如下$ ssh hostname。上面命令中,hostname是主机名,它可以是域名,也可能是 IP 地址或局域网内部的主机名。不指定用户名的情况下,将使用客户端的当前用户名,作为远程服务器的登录用户名。如果要指定用户名,可以采用下面的语法$ ssh user@hostname。上面的命令中,用户名和主机名写在一起了,之间使用@分隔。用户名也可以使用ssh的-l参数指定,这样的话,用户名和主机名就不用写在一起了$ ssh -l username host。ssh 默认连接服务器的22端口,-p参数可以指定其他端口$ ssh -p 8821 foo.com,上面命令连接服务器foo.com的8821端口。

    连接流程

    ssh 连接远程服务器后,首先有一个验证过程,验证远程服务器是否为陌生地址。如果是第一次连接某一台服务器,命令行会显示一段文字,表示不认识这台机器,提醒用户确认是否需要连接。

    The authenticity of host 'foo.com (192.168.121.111)' can't be established.
    ECDSA key fingerprint is SHA256:Vybt22mVXuNuB5unE++yowF7lgA/9/2bLSiO3qmYWBY.
    Are you sure you want to continue connecting (yes/no)?
    

    上面这段文字告诉用户,foo.com这台服务器的指纹是陌生的,让用户选择是否要继续连接(输入 yes 或 no)。所谓“服务器指纹”,指的是 SSH 服务器公钥的哈希值。每台 SSH 服务器都有唯一一对密钥,用于跟客户端通信,其中公钥的哈希值就可以用来识别服务器。下面的命令可以查看某个公钥的指纹。

    $ ssh-keygen -l -f /etc/ssh/ssh_host_ecdsa_key.pub
    256 da:24:43:0b:2e:c1:3f:a1:84:13:92:01:52:b4:84:ff   (ECDSA)
    

    上面的例子中,ssh-keygen -l -f命令会输出公钥/etc/ssh/ssh_host_ecdsa_key.pub的指纹。ssh 会将本机连接过的所有服务器公钥的指纹,都储存在本机的~/.ssh/known_hosts文件中。每次连接服务器时,通过该文件判断是否为陌生主机(陌生公钥)。
    在上面这段文字后面,输入yes,就可以将当前服务器的指纹也储存在本机~/.ssh/known_hosts文件中,并显示下面的提示。以后再连接的时候,就不会再出现警告了。

    Warning: Permanently added 'foo.com (192.168.121.111)' (RSA) to the list of known hosts
    

    然后,客户端就会跟服务器建立连接。接着,ssh 就会要求用户输入所要登录账户的密码。用户输入并验证密码正确以后,就能登录远程服务器的 Shell 了。

    服务器密钥变更

    服务器指纹可以防止有人恶意冒充远程主机。如果服务器的密钥发生变更(比如重装了 SSH 服务器),客户端再次连接时,就会发生公钥指纹不吻合的情况。这时,客户端就会中断连接,并显示一段警告信息。

    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    @    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
    Someone could be eavesdropping on you right now (man-in-the-middle attack)!
    It is also possible that the RSA host key has just been changed.
    The fingerprint for the RSA key sent by the remote host is
    77:a5:69:81:9b:eb:40:76:7b:13:04:a9:6c:f4:9c:5d.
    Please contact your system administrator.
    Add correct host key in /home/me/.ssh/known_hosts to get rid of this message.
    Offending key in /home/me/.ssh/known_hosts:36
    

    上面这段文字的意思是,该主机的公钥指纹跟~/.ssh/known_hosts文件储存的不一样,必须处理以后才能连接。这时,你需要确认是什么原因,使得公钥指纹发生变更,到底是恶意劫持,还是管理员变更了 SSH 服务器公钥。
    如果新的公钥确认可以信任,需要继续执行连接,你可以执行下面的命令,将原来的公钥指纹从~/.ssh/known_hosts文件删除$ ssh-keygen -R hostname
    上面命令中,hostname是发生公钥变更的主机名。除了使用上面的命令,你也可以手工修改known_hosts文件,将公钥指纹删除。删除了原来的公钥指纹以后,重新执行 ssh 命令连接远程服务器,将新的指纹加入known_hosts文件,就可以顺利连接了。

    执行远程命令

    SSH 登录成功后,用户就进入了远程主机的命令行环境,所看到的提示符,就是远程主机的提示符。这时,你就可以输入想要在远程主机执行的命令。另一种执行远程命令的方法,是将命令直接写在ssh命令的后面$ ssh user@hostname command。上面的命令会使得 SSH 在登录成功后,立刻在远程主机上执行命令command,下面是一个例子$ ssh user@hostname cat /etc/hosts
    上面的命令会在登录成功后,立即远程执行命令cat /etc/hosts。采用这种语法执行命令时,ssh 客户端不会提供互动式的 Shell 环境,而是直接远程命令的执行结果输出在命令行。但是,有些命令需要互动式的 Shell 环境,这时就要使用-t参数。

    # 报错
    $ ssh remote.server.com emacs
    emacs: standard input is not a tty
    # 不报错
    $ ssh -t server.example.com emacs
    

    上面代码中,emacs命令需要一个互动式 Shell,所以报错。只有加上-t参数,ssh 才会分配一个互动式 Shell。

    加密参数

    SSH 连接的握手阶段,客户端必须跟服务端约定加密参数集(cipher suite)。加密参数集包含了若干不同的加密参数,它们之间使用下划线连接在一起,下面是一个例子TLS_RSA_WITH_AES_128_CBC_SHA
    它的含义如下。

    • TLS:协议
    • RSA:密钥交换算法
    • AES:加密算法
    • 128:加密强度
    • CBC:加密模式
    • SHA:数字签名的 Hash 函数
      下面是一个例子,客户端向服务器发出的握手信息。
    Handshake protocol: ClientHello
        Version: TLS 1.2
        Random
            Client time: May 22, 2030 02:43:46 GMT
            Random bytes: b76b0e61829557eb4c611adfd2d36eb232dc1332fe29802e321ee871
        Session ID: (empty)
        Cipher Suites
            Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256”
            Suite: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
            Suite: TLS_RSA_WITH_AES_128_GCM_SHA256
            Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
            Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA
            Suite: TLS_RSA_WITH_AES_128_CBC_SHA
            Suite: TLS_RSA_WITH_3DES_EDE_CBC_SHA
            Suite: TLS_RSA_WITH_RC4_128_SHA
        Compression methods
            Method: null
        Extensions
            Extension: server_name
                Hostname: www.feistyduck.com
            Extension: renegotiation_info
            Extension: elliptic_curves
                Named curve: secp256r1
                Named curve: secp384r1
            Extension: signature_algorithms
                Algorithm: sha1/rsa
                Algorithm: sha256/rsa
                Algorithm: sha1/ecdsa
                Algorithm: sha256/ecdsa”
    

    上面的握手信息(ClientHello)之中,Cipher Suites字段就是客户端列出可选的加密参数集,服务器在其中选择一个自己支持的参数集。
    服务器选择完毕之后,向客户端发出回应。

    Handshake protocol: ServerHello
        Version: TLS 1.2
        Random
            Server time: Mar 10, 2059 02:35:57 GMT”
            Random bytes: 8469b09b480c1978182ce1b59290487609f41132312ca22aacaf5012
        Session ID: 4cae75c91cf5adf55f93c9fb5dd36d19903b1182029af3d527b7a42ef1c32c80
        Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
        Compression method: null
        Extensions
            Extension: server_name
            Extension: renegotiation_info”
    

    上面的回应信息(ServerHello)中,Cipher Suite字段就是服务器最终选定的加密参数。

    ssh 命令行配置项

    ssh 命令有很多配置项,修改它的默认行为,-c参数指定加密算法。下面命令指定使用加密算法blowfish或3des。

    $ ssh -c blowfish,3des server.example.com
    # 或者
    $ ssh -c blowfish -c 3des server.example.com
    

    -C参数表示压缩数据传输$ ssh -C server.example.com
    -d参数设置打印的 debug 信息级别,数值越高,输出的内容越详细$ ssh –d 1 foo.com
    -D参数指定本机的 Socks 监听端口,该端口收到的请求,都将转发到远程的 SSH 主机,又称动态端口转发,详见《端口转发》一章$ ssh -D 1080 server,上面命令将本机 1080 端口收到的请求,都转发到服务器server
    -R参数指定远程端口转发,详见《端口转发》一章,$ ssh -R 9999:targetServer:902 local,上面命令需在跳板服务器执行,指定本地计算机local监听自己的 9999 端口,所有发向这个端口的请求,都会转向 targetServer 的 902 端口。
    -L参数设置本地端口转发,详见《端口转发》一章$ ssh -L 9999:targetServer:80 user@remoteserver,上面命令中,所有发向本地9999端口的请求,都会经过remoteserver发往 targetServer 的 80 端口,这就相当于直接连上了 targetServer 的 80 端口。
    -X参数表示打开 X 窗口转发$ ssh -X server.example.com
    -f参数表示 SSH 连接在后台运行
    -F参数指定配置文件$ ssh -F /usr/local/ssh/other_config,上面命令指定使用配置文件other_config。
    -i参数用于指定私钥,意为“identity_file”,默认值为~/.ssh/id_dsa。注意,对应的公钥必须存放到服务器,详见《密钥登录》一章$ ssh -i my-key server.example.com
    -l参数指定远程登录的账户名

    $ ssh -l sally server.example.com
    # 等同于
    $ ssh sally@server.example.com
    

    -m参数指定校验数据完整性的算法(message authentication code,简称 MAC)$ ssh -m hmac-sha1,hmac-md5 server.example.com,上面命令指定数据校验算法为hmac-sha1或hmac-md5。
    -o参数用来指定一个配置命令$ ssh -o "Keyword Value",举例来说,配置文件里面有如下内容

    User sally
    Port 220
    

    通过-o参数,可以把上面两个配置命令从命令行传入$ ssh -o "User sally" -o "Port 220" server.example.com。使用等号时,配置命令可以不用写在引号里面,但是等号前后不能有空格$ ssh -o User=sally -o Port=220 server.example.com
    -p参数指定 SSH 客户端连接的服务器端口$ ssh -p 2035 server.example.com,上面命令连接服务器的2035端口。
    -q参数表示安静模式(quiet),不向用户输出任何警告信息,下面命令使用-q参数,只输出要求用户输入密码的提示。

    $ ssh –q foo.com
    root’s password:
    

    -t参数在 ssh 直接运行远端命令时,提供一个互动式 Shell,$ ssh -t server.example.com emacs
    -v参数显示详细信息$ ssh -v server.example.com
    -v可以重复多次,表示信息的详细程度,比如-vv和-vvv。

    $ ssh -vvv server.example.com
    # 或者
    $ ssh -v -v -v server.example.com
    

    -V参数输出 ssh 客户端的版本。

    $ ssh –V
    ssh: SSH Secure Shell 3.2.3 (non-commercial version) on i686-pc-linux-gnu
    

    -1参数指定使用 SSH 1 协议。-2参数指定使用 SSH 2 协议 $ ssh -2 server.example.com
    -4指定使用 IPv4 协议,这是默认值$ ssh -4 server.example.com。-6指定使用 IPv6 协议$ ssh -6 server.example.com

    客户端配置文件

    位置

    SSH 客户端的全局配置文件是/etc/ssh/ssh_config,**用户个人的配置文件在/.ssh/config**,优先级高于全局配置文件。除了配置文件,/.ssh目录还有一些用户个人的密钥文件和其他文件。下面是其中一些常见的文件。
    ~/.ssh/id_ecdsa:用户的 ECDSA 私钥。
    ~/.ssh/id_ecdsa.pub:用户的 ECDSA 公钥。
    ~/.ssh/id_rsa:用于 SSH 协议版本2 的 RSA 私钥。
    ~/.ssh/id_rsa.pub:用于SSH 协议版本2 的 RSA 公钥。
    ~/.ssh/identity:用于 SSH 协议版本1 的 RSA 私钥。
    ~/.ssh/identity.pub:用于 SSH 协议版本1 的 RSA 公钥。
    ~/.ssh/known_hosts:包含 SSH 服务器的公钥指纹。

    主机设置

    用户个人的配置文件~/.ssh/config,可以按照不同服务器,列出各自的连接参数,从而不必每一次登录都输入重复的参数。下面是一个例子。

    Host *
         Port 2222
    
    Host remoteserver
         HostName remote.example.com
         User neo
         Port 2112
    

    上面代码中,Host *表示对所有主机生效,后面的Port 2222表示所有主机的默认连接端口都是2222,这样就不用在登录时特别指定端口了。这里的缩进并不是必需的,只是为了视觉上,易于识别针对不同主机的设置。后面的Host remoteserver表示,下面的设置只对主机remoteserver生效。remoteserver只是一个别名,具体的主机由HostName命令指定,User和Port这两项分别表示用户名和端口。这里的Port会覆盖上面Host *部分的Port设置。以后,登录remote.example.com时,只要执行ssh remoteserver命令,就会自动套用 config 文件里面指定的参数。单个主机的配置格式如下。

    $ ssh remoteserver
    # 等同于
    $ ssh -p 2112 neo@remote.example.com
    

    Host命令的值可以使用通配符,比如Host *表示对所有主机都有效的设置,Host *.edu表示只对一级域名为.edu的主机有效的设置。它们的设置都可以被单个主机的设置覆盖。

    配置命令的语法

    ssh 客户端配置文件的每一行,就是一个配置命令。配置命令与对应的值之间,可以使用空格,也可以使用等号。#开头的行表示注释,会被忽略。空行等同于注释。

    Compression yes
    # 等同于
    Compression = yes
    

    主要配置命令

    下面是 ssh 客户端的一些主要配置命令,以及它们的范例值。
    AddressFamily inet:表示只使用 IPv4 协议。如果设为inet6,表示只使用 IPv6 协议。
    BindAddress 192.168.10.235:指定本机的 IP 地址(如果本机有多个 IP 地址)。
    CheckHostIP yes:检查 SSH 服务器的 IP 地址是否跟公钥数据库吻合。
    Ciphers blowfish,3des:指定加密算法。
    Compression yes:是否压缩传输信号。
    ConnectionAttempts 10:客户端进行连接时,最大的尝试次数。
    ConnectTimeout 60:客户端进行连接时,服务器在指定秒数内没有回复,则中断连接尝试。
    DynamicForward 1080:指定动态转发端口。
    GlobalKnownHostsFile /users/smith/.ssh/my_global_hosts_file:指定全局的公钥数据库文件的位置。
    Host server.example.com:指定连接的域名或 IP 地址,也可以是别名,支持通配符。Host命令后面的所有配置,都是针对该主机的,直到下一个Host命令为止。
    HostKeyAlgorithms ssh-dss,ssh-rsa:指定密钥算法,优先级从高到低排列。
    HostName myserver.example.com:在Host命令使用别名的情况下,HostName指定域名或 IP 地址。
    IdentityFile keyfile:指定私钥文件。
    LocalForward 2001 localhost:143:指定本地端口转发。
    LogLevel QUIET:指定日志详细程度。如果设为QUIET,将不输出大部分的警告和提示。
    MACs hmac-sha1,hmac-md5:指定数据校验算法。
    NumberOfPasswordPrompts 2:密码登录时,用户输错密码的最大尝试次数。
    PasswordAuthentication no:指定是否支持密码登录。不过,这里只是客户端禁止,真正的禁止需要在 SSH 服务器设置。
    Port 2035:指定客户端连接的 SSH 服务器端口。
    PreferredAuthentications publickey,hostbased,password:指定各种登录方法的优先级。
    Protocol 2:支持的 SSH 协议版本,多个版本之间使用逗号分隔。
    PubKeyAuthentication yes:是否支持密钥登录。这里只是客户端设置,还需要在 SSH 服务器进行相应设置。
    RemoteForward 2001 server:143:指定远程端口转发。
    SendEnv COLOR:SSH 客户端向服务器发送的环境变量名,多个环境变量之间使用空格分隔。环境变量的值从客户端当前环境中拷贝。
    ServerAliveCountMax 3:如果没有收到服务器的回应,客户端连续发送多少次keepalive信号,才断开连接。该项默认值为3。
    ServerAliveInterval 300:客户端建立连接后,如果在给定秒数内,没有收到服务器发来的消息,客户端向服务器发送keepalive消息。如果不希望客户端发送,这一项设为0。
    StrictHostKeyChecking yes:yes表示严格检查,服务器公钥为未知或发生变化,则拒绝连接。no表示如果服务器公钥未知,则加入客户端公钥数据库,如果公钥发生变化,不改变客户端公钥数据库,输出一条警告,依然允许连接继续进行。ask(默认值)表示询问用户是否继续进行。
    TCPKeepAlive yes:客户端是否定期向服务器发送keepalive信息。
    User userName:指定远程登录的账户名。
    UserKnownHostsFile /users/smith/.ssh/my_local_hosts_file:指定当前用户的known_hosts文件(服务器公钥指纹列表)的位置。
    VerifyHostKeyDNS yes:是否通过检查 SSH 服务器的 DNS 记录,确认公钥指纹是否与known_hosts文件保存的一致。

    SSH 密钥登录

    SSH 默认采用密码登录,这种方法有很多缺点,简单的密码不安全,复杂的密码不容易记忆,每次手动输入也很麻烦。密钥登录是更好的解决方案。

    密钥是什么

    密钥(key)是一个非常大的数字,通过加密算法得到。对称加密只需要一个密钥,非对称加密需要两个密钥成对使用,分为公钥(public key)和私钥(private key)。SSH 密钥登录采用的是非对称加密,每个用户通过自己的密钥登录。其中,私钥必须私密保存,不能泄漏;公钥则是公开的,可以对外发送。它们的关系是,公钥和私钥是一一对应的,每一个私钥都有且仅有一个对应的公钥,反之亦然。如果数据使用公钥加密,那么只有使用对应的私钥才能解密,其他密钥都不行;反过来,如果使用私钥加密(这个过程一般称为“签名”),也只有使用对应的公钥解密。

    密钥登录的过程

    SSH 密钥登录分为以下的步骤。
    预备步骤,客户端通过ssh-keygen生成自己的公钥和私钥。
    第一步,手动将客户端的公钥放入远程服务器的指定位置。
    第二步,客户端向服务器发起 SSH 登录的请求。
    第三步,服务器收到用户 SSH 登录的请求,发送一些随机数据给用户,要求用户证明自己的身份。
    第四步,客户端收到服务器发来的数据,使用私钥对数据进行签名,然后再发还给服务器。
    第五步,服务器收到客户端发来的加密签名后,使用对应的公钥解密,然后跟原始数据比较。如果一致,就允许用户登录。

    ssh-key命令:生成密钥

    基本用法

    密钥登录时,首先需要生成公钥和私钥。OpenSSH 提供了一个工具程序ssh-keygen命令,用来生成密钥。直接输入ssh-keygen,程序会询问一系列问题,然后生成密钥$ ssh-keygen。通常做法是使用-t参数,指定密钥的加密算法$ ssh-keygen -t dsa。上面示例中,-t参数用来指定密钥的加密算法,一般会选择dsa算法或rsa算法。注意,这个参数没有默认值。输入上面的命令以后,ssh-keygen会要求用户回答一些问题。

    $ ssh-keygen -t dsa
    Generating public/private dsa key pair.
    Enter file in which to save the key (/home/username/.ssh/id_dsa):  press ENTER
    Enter passphrase (empty for no passphrase): ********
    Enter same passphrase again: ********
    Your identification has been saved in /home/username/.ssh/id_dsa.
    Your public key has been saved in /home/username/.ssh/id_dsa.pub.
    The key fingerprint is:
    14:ba:06:98:a8:98:ad:27:b5:ce:55:85:ec:64:37:19 username@shell.isp.com
    

    上面示例中,执行ssh-keygen命令以后,会出现第一个问题,询问密钥保存的文件名,默认是~/.ssh/id_dsa文件,这个是私钥的文件名,对应的公钥文件~/.ssh/id_dsa.pub是自动生成的。用户的密钥一般都放在主目录的.ssh目录里面。如果选择rsa算法,生成的密钥文件默认就会是~/.ssh/id_rsa(私钥)和~/.ssh/id_rsa.pub(公钥)。接着,就会是第二个问题,询问是否要为私钥文件设定密码保护(passphrase)。这样的话,即使入侵者拿到私钥,还是需要破解密码。如果为了方便,不想设定密码保护,可以直接按回车键,密码就会为空。后面还会让你再输入一次密码,两次输入必须一致。注意,这里“密码”的英文单词是 passphrase,这是为了避免与 Linux 账户的密码单词 password 混淆,表示这不是用户系统账户的密码。最后,就会生成私钥和公钥,屏幕上还会给出公钥的指纹,以及当前的用户名和主机名作为注释,用来识别密钥的来源。公钥文件和私钥文件都是文本文件,可以用文本编辑器看一下它们的内容。公钥文件的内容类似下面这样。

    ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAvpB4lUbAaEbh9u6HLig7amsfywD4fqSZq2ikACIUBn3GyRPfeF93l/
    weQh702ofXbDydZAKMcDvBJqRhUotQUwqV6HJxqoqPDlPGUUyo8RDIkLUIPRyq
    ypZxmK9aCXokFiHoGCXfQ9imUP/w/jfqb9ByDtG97tUJF6nFMP5WzhM= username@shell.isp.com
    

    上面示例中,末尾的username@shell.isp.com是公钥的注释,用来识别不同的公钥,表示这是哪台主机(shell.isp.com)的哪个用户(username)的公钥,不是必需项。注意,公钥只有一行。因为它太长了,所以上面分成三行显示。
    下面的命令可以列出用户所有的公钥$ ls -l ~/.ssh/id_*.pub
    生成密钥以后,建议修改它们的权限,防止其他人读取。

    $ chmod 600 ~/.ssh/id_rsa
    $ chmod 600 ~/.ssh/id_rsa.pub
    

    配置项

    ssh-keygen的命令行配置项,主要有下面这些。
    (1)-b
    -b参数指定密钥的二进制位数。这个参数值越大,密钥就越不容易破解,但是加密解密的计算开销也会加大。一般来说,-b至少应该是1024,更安全一些可以设为2048或者更高。
    (2)-C
    -C参数可以为密钥文件指定新的注释,格式为username@host。下面命令生成一个4096位 RSA 加密算法的密钥对,并且给出了用户名和主机名$ ssh-keygen -t rsa -b 4096 -C "your_email@domain.com"
    (3)-f 参数指定生成的私钥文件$ ssh-keygen -t dsa -f mykey。上面命令会在当前目录生成私钥文件mykey和公钥文件mykey.pub。
    (4)-F参数检查某个主机名是否在known_hosts文件里面$ ssh-keygen -F example.com
    (5)-N参数用于指定私钥的密码(passphrase)$ ssh-keygen -t dsa -N secretword
    (6)-p参数用于重新指定私钥的密码(passphrase)。它与-N的不同之处在于,新密码不在命令中指定,而是执行后再输入。ssh 先要求输入旧密码,然后要求输入两遍新密码。
    (7)-R参数将指定的主机公钥指纹移出known_hosts文件$ ssh-keygen -R example.com
    (8)-t参数用于指定生成密钥的加密算法,一般为dsa或rsa。

    手动上传公钥

    生成密钥以后,公钥必须上传到服务器,才能使用公钥登录。OpenSSH 规定,用户公钥保存在服务器的~/.ssh/authorized_keys文件。你要以哪个用户的身份登录到服务器,密钥就必须保存在该用户主目录的~/.ssh/authorized_keys文件。只要把公钥添加到这个文件之中,就相当于公钥上传到服务器了。每个公钥占据一行。如果该文件不存在,可以手动创建。用户可以手动编辑该文件,把公钥粘贴进去,也可以在本机计算机上,执行下面的命令$ cat ~/.ssh/id_rsa.pub | ssh user@host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
    上面示例中,user@host要替换成你所要登录的用户名和主机名。注意,authorized_keys文件的权限要设为644,即只有文件所有者才能写。如果权限设置不对,SSH 服务器可能会拒绝读取该文件$ chmod 644 ~/.ssh/authorized_keys
    只要公钥上传到服务器,下次登录时,OpenSSH 就会自动采用密钥登录,不再提示输入密码。

    $ ssh -l username shell.isp.com
    Enter passphrase for key '/home/you/.ssh/id_dsa': ************
    Last login: Mon Mar 24 02:17:27 2014 from ex.ample.com
    shell.isp.com>
    

    上面例子中,SSH 客户端使用私钥之前,会要求用户输入密码(passphrase),用来解开私钥。

    ssh-copy-id 命令:自动上传公钥

    OpenSSH 自带一个ssh-copy-id命令,可以自动将公钥拷贝到远程服务器的/.ssh/authorized_keys文件。如果/.ssh/authorized_keys文件不存在,ssh-copy-id命令会自动创建该文件。用户在本地计算机执行下面的命令,就可以把本地的公钥拷贝到服务器$ ssh-copy-id -i key_file user@host
    上面命令中,-i参数用来指定公钥文件,user是所要登录的账户名,host是服务器地址。如果省略用户名,默认为当前的本机用户名。执行完该命令,公钥就会拷贝到服务器。注意,公钥文件可以不指定路径和.pub后缀名,ssh-copy-id会自动在~/.ssh目录里面寻找$ ssh-copy-id -i id_rsa user@host
    上面命令中,公钥文件会自动匹配到~/.ssh/id_rsa.pub。ssh-copy-id会采用密码登录,系统会提示输入远程服务器的密码。
    注意,ssh-copy-id是直接将公钥添加到authorized_keys文件的末尾。如果authorized_keys文件的末尾不是一个换行符,会导致新的公钥添加到前一个公钥的末尾,两个公钥连在一起,使得它们都无法生效。所以,如果authorized_keys文件已经存在,使用ssh-copy-id命令之前,务必保证authorized_keys文件的末尾是换行符(假设该文件已经存在)。

    ssh-agent 命令,ssh-add 命令

    基本用法

    私钥设置了密码以后,每次使用都必须输入密码,有时让人感觉非常麻烦。比如,连续使用scp命令远程拷贝文件时,每次都要求输入密码。ssh-agent命令就是为了解决这个问题而设计的,它让用户在整个 Bash 对话(session)之中,只在第一次使用 SSH 命令时输入密码,然后将私钥保存在内存中,后面都不需要再输入私钥的密码了。
    第一步,使用下面的命令新建一次命令行对话$ ssh-agent bash
    上面命令中,如果你使用的命令行环境不是 Bash,可以用其他的 Shell 命令代替。比如zsh和fish。如果想在当前对话启用ssh-agent,可以使用下面的命令$ evalssh-agent``。
    上面命令中,ssh-agent会先自动在后台运行,并将需要设置的环境变量输出在屏幕上,类似下面这样。

    $ ssh-agent
    SSH_AUTH_SOCK=/tmp/ssh-barrett/ssh-22841-agent; export SSH_AUTH_SOCK;
    SSH_AGENT_PID=22842; export SSH_AGENT_PID;
    echo Agent pid 22842;
    

    eval命令的作用,就是运行上面的ssh-agent命令的输出,设置环境变量。
    第二步,在新建的 Shell 对话里面,使用ssh-add命令添加默认的私钥(比如/.ssh/id_rsa,或/.ssh/id_dsa,或/.ssh/id_ecdsa,或/.ssh/id_ed25519)。

    $ ssh-add
    Enter passphrase for /home/you/.ssh/id_dsa: ********
    Identity added: /home/you/.ssh/id_dsa (/home/you/.ssh/id_dsa)
    

    上面例子中,添加私钥时,会要求输入密码。以后,在这个对话里面再使用密钥时,就不需要输入私钥的密码了,因为私钥已经加载到内存里面了。如果添加的不是默认私钥,ssh-add命令需要显式指定私钥文件$ ssh-add my-other-key-file。上面的命令中,my-other-key-file就是用户指定的私钥文件。
    第三步,使用 ssh 命令正常登录远程服务器$ ssh remoteHost。上面命令中,remoteHost是远程服务器的地址,ssh 使用的是默认的私钥。这时如果私钥设有密码,ssh 将不再询问密码,而是直接取出内容里面的私钥。如果要使用其他私钥登录服务器,需要使用 ssh 命令的-i参数指定私钥文件$ ssh –i OpenSSHPrivateKey remoteHost。最后,如果要退出ssh-agent,可以直接退出子 Shell(按下 Ctrl + d),也可以使用下面的命令$ ssh-agent -k

    ssh-add命令

    ssh-add命令用来将私钥加入ssh-agent,它有如下的参数。
    (1)-d参数从内存中删除指定的私钥。
    $ ssh-add -d name-of-key-file
    (2)-D参数从内存中删除所有已经添加的私钥。
    $ ssh-add -D
    (3)-l参数列出所有已经添加的私钥。
    $ ssh-add -l

    关闭密码登录

    为了安全性,启用密钥登录之后,最好关闭服务器的密码登录。对于 OpenSSH,具体方法就是打开服务器 sshd 的配置文件/etc/ssh/sshd_config,将PasswordAuthentication这一项设为no PasswordAuthentication no,修改配置文件以后,不要忘了重新启动 sshd,否则不会生效。

    展开全文
  • Oracle客户端使用

    万次阅读 2017-09-30 14:49:12
    Oracle客户端使用1.Oracle客户端的安装及配置大部分时间,Oracle数据库我们都是安装在服务器端,然后再在本地使用其他工具进行连接。例如:PL/SQL、Navicat Premium等其他工具来进行连接。但是Oracle与mysql和...
  • Linux学习之客户端软件介绍

    千次阅读 2019-03-01 23:42:13
    本篇文章所述的客户端软件指使用Xshell连接远程Linux虚拟机,使用Xftp作为文件传输传输工具,至于其它的同款类似软件想了解得需要自行百科了。经过别人的介绍和这几天的使用发现这款软件用起来体验还是不错的,首先...
  • 为了确定PHP代码为什么不能在JavaScript代码中运行,我们需要了解什么是客户端和服务器端语言,以及它们如何工作。 Server-side languages (PHP etc.) : They retrieve records from databases, maintain state ...
  • 客户端测试小结

    2018-07-22 15:39:00
    今天台风天气,外面也不好出去,正好总结下客户端测试的8个月工作。客户端测试又称手机测试顾名思义乃是当前最流行的两端android&IOS。客户端应该如何测试呢?首先还是充分了解需求,挖掘需求,设计编写每一条...
  • 但是SSL真正需要提供什么? 安全套接字层(SSL)是一种安全协议,可以: 加密通过网络发送的信息。 验证发送给收件人的邮件是否已被篡改。 验证服务器身份以防止服务器欺骗。 使用SSL 3.0验证客户端身份...
  • HTTP协议理解及服务端与客户端的设计实现

    万次阅读 多人点赞 2019-06-20 19:05:05
    本文主要帮助读者理解 HTTP 的协作原理、HTTP 相关的各层协议,在服务端和客户端的架构设计和一些优化的技巧,本文中主要讲述逻辑思想和协议远离,会使用部分 Java 代码,但会有详细的讲解,非开发应该也读的明白。...
  • HTTP 404错误你知道是什么意思

    千次阅读 2021-01-13 13:05:38
    那么404到底是什么意思,为什么会提示404错误呢? 通常在网站目标页面被更改或移除后,就会显示404错误页面。有时候客户端输入页面地址错误后,也会显示404错误页面。404是一个http错误代码,即请求的网页内容不存在...
  • PC客户端测试

    千次阅读 2020-06-01 17:46:32
    PC客户端测试的要点主要有以下: 一级测试点 二级测试点 安装测试 首次安装(exe和msi格式的不同) 安装程序权限检查 软件安装包的描述和属性信息 静默安装和非静默安装测试 有UAC安装、无UAC...
  • 在微服务里面,由服务端,客户端,注册中心三要素组成,以滴滴平台为例,这三要素的运行,最重要的就是注册中心,为什么呢,因为服务端,客户端,你可以少一个两个,并不会影响到整体滴滴平台和广大人民群众的出行,...
  • hive 服务器客户端 理解

    千次阅读 2018-12-13 13:48:56
    在hive的分布式安装中,网上对于客户端和服务器的理解感觉并没有很清晰。接下来将简单说一下个人理解,如果有错,请各位大佬尽管指出,只是一种学习讨论罢了。 第一,在安装hive的各个节点(包括master和slave)上...
  • 什么是cookie 1,存储在浏览器的一段字符串,浏览器为每个域名都存了一段cookie 2,跨域不共享 3,可以存储结构化,格式如下: 4,每次发送http请求,会将请求域的cookie一起发送给server 5,server可以修改cookie...
  • 客户端负载均衡(Ribbon)

    万次阅读 多人点赞 2019-01-22 15:04:11
    客户端负载均衡 Ribbon负载均衡示例搭建 创建服务提供者 引入依赖 添加配置 服务提供者 创建启动类 启动服务 服务消费者 引入Ribbon依赖 添加配置 使用Ribbon客户端 切换Ribbon负载均衡策略 自定义...
  • 06-01_Redis_客户端_RDM的安装与使用

    千次阅读 2019-10-30 11:51:51
    6 客户端 6.1 RDM的安装与使用 Redis Desktop Manager(RDM)是一款Windows的Redis客户端工具。 6.1.1 RDM的安装 1:绑定开放的IP地址 默认情况下,Redis是不允许远程访问的,因此需要在Redis的配置文件中增加配置项:...
  • JavaScript是什么意思

    千次阅读 2020-09-10 14:20:48
    它是轻量级的,最常用作网页的一部分,其实现允许客户端脚本与用户交互并生成动态页面。它是一种具有面向对象功能的解释型编程语言。 JavaScript是一种非常着名的编程语言,最初是在二十年前开始的,其动机是使网页...
  • frp连接Linux客户端

    千次阅读 2019-07-29 11:05:09
    简介:本文最终目的是在CentOS 7 64bit 下部署frp客户端。 作者:lxy frp下载 frp官方git下载: https://github.com/fatedier/frp/releases (包含了linux、windows等平台) frp服务端搭建: frp服务器必须具有...
  •  通过cookie的方式存储信息,可能会存在一点定的安全性,因为所有的信息都是写在客户端的,客户可能会对这些信息进行修改或清除。然后就又出现session的方式用于保存用户行为。  具体来说cookie机制采用的是在...
  • 心跳超时指的是:针对某个在线的客户端(TCP连接),ESFramework服务端在指定的时间内,没有收到来自该客户端的任何消息,则认为该客户端已经掉线。  为什么需要心跳机制了?因为针对某些客户端掉线(可能是因为...
  • restful什么意思This article was originally published on codurance.com. 本文最初在codurance.com上发布 。 Last month I attended Fast Track to RESTful Microservices training at Skillsmatter. During the...
  • PLC作为Modbus TCP客户端

    千次阅读 2020-11-27 15:23:53
    PLC作为Modbus TCP客户端,Modbus Slave作为服务器
  • 有没有大佬指教下怎么解决啊 <p style="text-align:center"><img alt="" height="3648" src="https://img-ask.csdnimg.cn/upload/1621420902650.jpg" width="2736" /></p>  </p>
  • 文章目录NFS(文件共享)关于NFS的基本配置和权限的设置服务端配置客户端配置基于kerberos的NFS服务端配置客户端配置: NFS(文件共享) 关于NFS的基本配置和权限的设置 nfs相当于类unix之间一种文件的共享 只要...
  • Oracle数据库 红油桶客户端PL sql Developer 免安装,解压缩修改配置文件tnsname.ora 文件配置一下服务命名地址就可以了直接用。
  • 本地的客户端没有配置客户端的环境变量,只在自己的电脑工具上可以连接 二、解决 打开电脑的配置环境变量界面如下图: 新增3个环境变量: 变量名:ORACLE_HOME 变量值:D:\Program Files\oracle(如果没有安装...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 179,834
精华内容 71,933
关键字:

修改客户端是什么意思