精华内容
下载资源
问答
  • 2022-03-28 13:48:12

    大家好!我现如今已经学习到Linux-Redis了,在前期安装编译环境真的是痛疼,特别是这个gcc,看了网上很多水文,确实很水。今天在这里把我失败N多次的成功经验分享给大家!

    程序员废话不多说,直接上教程

    安装gcc(C语言的编译环境)

    yum install gcc

    如果通过yum安装源出现如下错误

    [root@localhost tmp]# yum install gcc
    Loaded plugins: fastestmirror, refresh-packagekit, security
    Determining fastest mirrors
    YumRepo Error: All mirror URLs are not using ftp, http[s] or file.
     Eg. Invalid release/repo/arch combination/
    removing mirrorlist with no valid mirrors: /var/cache/yum/x86_64/6/base/mirrorlist.txt
    Error: Cannot find a valid baseurl for repo: base

    原因:2020年11月30日开始 centos6各大开源镜像站已经停止维护了。需要配置阿里云镜。解决方式:

    依次执行!!

    1、通过执行如下命令修改fastestmirror.conf的配置参数

    sed -i "s|enabled=1|enabled=0|g" /etc/yum/pluginconf.d/fastestmirror.conf

    2、备份文件

    mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak

    3.国内建议使用阿里云镜像,执行如下

    curl -o /etc/yum.repos.d/CentOS-Base.repo https://www.xmpan.com/Centos-6-Vault-Aliyun.repo

    然后!!!

    访问网址:https://www.xmpan.com/Centos-6-Vault-Aliyun.repo

    会自动下载一个文件!

    然后在linux执行:

    vim /etc/yum.repos.d/CentOS-Base.repo

    将下载的文件的所有内容全部复制到执行后的 vim /etc/yum.repos.d/CentOS-Base.repo中

    保存退出后再执行yum install gcc!

    全部选y

    注意:一定要检查一下下载文件的内容是否完整无缺的复制到了,缺一点都会报错

    例如:

    Loaded plugins: refresh-packagekit, security
    
    
    File contains no section headers.
    file: file:/etc/yum.repos.d/CentOS-Base.repo, line: 1
    'entOS-Base.repo\n'

    精细手打不易,欢迎留言

    更多相关内容
  • revolver-webpack-plugin

    2021-05-24 12:29:02
    当您需要跨不同目录解析文件(如果存在)时(例如,在为站点使用不同主题或语言环境时,解决或适用于您的用例),这将非常有用。 假设您有一个包含文件a.js ,该文件源目录中使用以下配置: import * from '...
  • 它将保留用作图形数据的表元素页面上完整无缺,这既可以提高可访问性,又可以设备上不存在JavaScript或应用案例认为适合图形中显示数据时进行智能后备,例如小屏幕上。 用法 您的页面中包含grafici.js ...
  • 为什么选择LaMode ÀLaMode是基于AST的编译器的一种简洁,快速,轻巧的替代品。 如果您只想import和export语句,请不要继续使用Babel而不尊重自己,并立即切换到ÀLaMode 。 我说什么继续阅读。 整洁 源代码几乎...
  • 为什么这里把月薪定义30K,因为我觉得,30K是比较资深的工程师的合理薪酬,薪水再高的,估计一般都会有个经理什么的头衔了,就能简单的算做是工程师了。 老板不会无缘无故给我们加薪,但我们必须具备让老板给...

    点击上方“小麦大叔”,选择“置顶/星标公众号”

    福利干货,第一时间送达

    这里主要以个人经历谈谈年轻电子工程师作为电子新手,需要开始全新的技术生涯;面临的困惑、最关心的问题、对未来的期待。

    中国缺少什么样的电子工程师?中国缺少满嘴胡须的电子工程师;中国缺少在一个行业专注几十年的资深电子技术专家;中国缺少知识全面,做事精密细致的电子系统工程师。

    1. 电子工程师矛盾心态——电子新手新没事做,没人教,工作没有技术含量?

    电子新手往往心浮气躁,拒绝进步,拒绝沉淀,害怕丢脸。记住每一个让你丢脸的人,他们是你的贵人。感激那些给他难堪的人;感激那些给你启发的老师。电子 研发工作上的时忙时闲,是很正常的事情。缺乏对电子行业的整体认识让新手觉得没有事情做;缺乏与同事的良好沟通让新手没有人去教;缺乏对工作的深入分析让 新手觉得没有事情做。学会找事情做,虚心诚恳地去观察,去问问题,就可以摆脱“没事做,没人教”矛盾心态。

    2. 大城市与小城市的电子工程师那个更好?

    北上广深是四个电子行业最集中的城市,工作机会很多,不少跨国公司的研发中心或总部大部分在这四个城市。大城市房价贵,交通费用高,工作节奏快,压力大, 但选择的余地也大。小城市除了工作外,则更适合生活。菁菁木华早期在一个小城市,能够走路15分钟上班,坚持每天早上去晨泳,春夏秋冬从不间断,2006 年阴差阳错的来到了上海的市中心上班一直到现在。总体来说,大小城市各有各的好处,都是一种活法。如果你看中工作,看中事业,大城市机会多,可能更适合 你;如果想找更适合生活的地方,可以选择去小城市发展。

    3. 大公司与小公司的电子工程师那个更好?

    电子新手在刚开始工作的时候尽量选择大公司。大公司稳定,里面积淀的电子高手很多,有更多机会去学习技术,同时学习他们的为人处世之道。如果能进入外企待 3到5年更好,完整的工作流程及鲜明的企业文化可以塑造你的好习惯,让你一辈子受益无穷。在珠三角的大型电子公司,里面有50多位电子研发工程师;到上海 则是进入一家国际性的大公司,里面的硬件、软件系统的高手更多,不少是从IBM、GE等跳槽过来的,海龟、博士也一大把。不过,个人能力到了一定的程度也 许可以去小公司,那将会是另外一片天空。

    4. 偏硬件与偏软件的电子工程师那个更好?

    一般来说,同样长的工作年份,偏软件工作的工资比偏硬件的稍微高一些;在数量上,偏软件的职位会比偏硬件的职位多;偏软件的职位在行业经验上的积累会影响 职位的跃迁;偏硬件的长远来讲更有发展前途,更方便以后转行,而且可以寻找到更多乐趣;真正的高手是软硬兼通的。菁菁木华在一度在偏硬偏软中徘徊,艰难的 勉强的选择了偏硬,发现还真适合自己。

    5. 电子技术学习该Focus深度还是Focus广度?

    纯粹的高深技术,并不能够给你带来财富。有不少电子新手,总以为学会了ARM、FPGA,会绘制10层或更多层电路板,就一定可以带来高薪,其实不然。技 术是相通的,全身心的投入聚焦去学单个的技术都很容易。把握当下和行业特点,结合实际的去钻研技术才最稳妥。太多的高深技术在睡觉。深度不一定有用,广度 也不一定有用,能够商业化并市场化的技术最有用。

    6. 与人沟通与技术精通,对电子工程师那个更重要?

    不少工程师一味的专注技术,忽视了与人沟通的重要性,长时间得不到公司的重用;更多的工程师以为掌握了热门了技术,如智能手机,无线通信等,就一定能够改 变他们的生活,让他们活的更有成就感。其实,结合自身的实际去专注在自身的行业核心技术的掌握,不断更新自我观念,提高自身修养水平,反省与人打交道的方 式方法,这样一个电子工程师才有更好的前景。很多时候,与人沟通比技术精通对一个电子工程师更重要。

    7. 如何成为电子工程师高手?

    电子工程师的工作就是将一堆器件搭在一起,注入思想(程序),完成这些器件分离时无法完成的功能,做出一个能够商业化的成品。技术高手需要持续的积累。学习态度重要,学习的方法重要,学习的环境及好师傅带更重要,自行总结自行去悟最重要——也就是在掌握一定的基础知识后,不断领悟。专注在一个行业,准备 好奋斗十年,或至少3~5年来掌握该行业的核心技术;勤于思考,要常常有灵机一动感觉;勤于动手,干什么像什么,能发现并对粗制滥造深恶痛绝,对精致严谨 一往情深,相信数年之后你一定成为电子高手。

    8. 什么样的电子工程师最吃香?

    电子工程师的综合素质在普通提升。精通英语或者其他的第二外语,计算机操作非常熟练,善于与人沟通,在一个领域有所建树,对电子行业系统有比较充分的了 解,并能持续不断学习的电子工程师最吃香。也就是说,“多面手电子工程师”最吃香。做合适的项目,遇到合适的上司,从技术走向高层,往往是可欲不可求的。能否进入到心仪的公司除了自身的努力之外,缘分是很重要的。

    9. 技术深度发展转行的途径是什么?

    从硬件或者软件,升级为做固件工程师;从固件工程师,升级为系统架构工程师;从硬件转为软件,从软件转为测试;电子工程师根据实际的情况和个人的兴趣爱 好,看中时机转行说不定发现另一个天空。我身边就有不少同事,转行很成功。一位同事从嵌入式软件工程师转去做测试,并成为这个嵌入式软件测试领域的高手, 在公司得到重用。

    10. 放弃技术转行的途径是什么?

    试着想想电子产业生态系统的每一个环节,想想是否有合适自己的位置?从电子工程师转行做市场,从电子工程师转行做管理,从电子工程师转行做生产、质量管 理……,这些都是路。高中同学从市场转到做海外市场的有几个,遨游在孟加拉,俄罗斯,有一个还当上了区域市场经理。转行做管理是一条最容易想到的路,但往 往可遇不可求,僧多粥少。从电子工程师转行的途径还有很多,需要根据自身和行业的情况进行选择。

    11. 电子行业的趋势是什么?

    电脑、汽车、家电、通信、工业、交通、航空、多媒体音频视频、医疗、电源、微电子,每个行业都在智能化、网络化、无线化、微型化。在每一个行业都有不少高端具有核心竞争力并极度挣钱的杰出公司。在一个行业专注几年,掌握该行业的核心技术,你的未来的前途将会更广阔。

    12. 电子技术的趋势是什么?

    电子技术的五个时代已经来临:Wireless时代、FPGA时代、Linux时代、Smartphone时代、Audio-Video时代。在任何热 门领域的一个技术点有所精通,你都是了不起的。在未来的很多年,你就不怕担心被淘汰。我的一个大学同学,毕业以后一直专注做音频,现在已经是小有成就了。

    13. 杯具的电子工程师深层次的原因是什么?

    杯具人生,鸡肋生活的真正原因是:除遗传外,脾气太坏、懒、方向错、方法错,没坚持,害怕变化。脾气来了、福气没了,想想是否具有癌症性格?每个人都需要 建立一个社会支持系统,有两三个可以让你倾诉的好友或家人;追求完美的人,学会了欣赏自己,宽容别人,把标准降低,生活中的开心就会多很多;容易消极的人 如果学会了得失的转换,就会开朗很多。生活累,少数人为了生存,多数人为了攀比。没有一个人的生命是完整无缺的,每个人多少少了一些东西。有人夫妻恩爱、 月入数十万,却没有儿女;有人才貌双全、能干多财,情路上却是坎坷难行;有人家财万贯,却是子孙不孝;有人看似好命,却是一辈子脑袋空空。每个人的生命, 都被上苍划上了一道缺口,你不想要它,它却如影随形。以前我也痛恨我人生中的缺失,但现在却能宽心接受。因为,我体认到生命中的缺口,彷若背上的一根刺, 时时提醒我们谦卑,要懂得怜恤,拥有一颗朴素的心。

    14. 如何获取更多的财富,渠道是什么?

    在规则中犯规地寻找夹缝。一般来说,有一定技术背景,良好的综合能力,跳槽是涨薪水的最快的方式;有了一定原始积累后,开源节流,省钱秘籍,卖服务,卖产 品,卖创意,以钱生钱搞投资;在电子行业的夹缝中,寻找挣钱的机会。人一出生就沦陷了,沦陷在了各种各样的规则当中,情场的、职场的、商场的、官场的…… 面对生命的幻境,每个人在清醒的时候都想挣脱,每用力挣扎一下,反而是陷得越深!无形的,有形的,看得见的,看不见的,尽是规则!电子行业的机会很多,就 看你能否在规则中犯规地寻找夹缝;随着对社会的深入了解,你会发现获取财富的通道很多。

    我们可以失败十次一百次,我们只需要成功一次,这辈子也许就够了,我们需要坚持到能够成功的那一刻。

    15. Work and Life balance 工作生活如何平衡?

    仔细想想:我们活着到底为了什么?

    年龄大了,才明白人活着除了为国家之外,就是为了儿女。即使为了自己的发展,也不要耽误了你的下一代。一位加拿大美籍华人同事在上海就谈到,他很多的朋友,由于工作太忙,在子女教育上出现了问题。现在后悔都来不及。为国家培养更多的后备精英也是在为国家做贡献。

    生活上:人生的境界与你的痛苦是成反比的。

    有些黑暗,只能自己穿越。有些痛苦,只能自己体验。有些孤独,只能自己品尝。但是穿过黑暗,我们一定能感受到阳光的温暖。走出痛苦,我们一定能企及成长的高度。告别孤独,我们一定也能收获心灵的深度。

    工作上:别把自己当回事,没有你地球照样转!

    铁打的兵营,流水的兵;过去的事,过去的人。其实很多事,回头看看,也就那回事。为了自己的理想,想动就动吧。

    拿素心待人,凭技术生存,靠实力发展,用事实说话!聚焦之后再聚焦,最后是一点突破.....

    16. 月薪30K+的电子工程师应具备什么?

    薪水和收入,是和大家的生活、工作密切相关的永恒的话题。对于我们绝大部分打工者,我们基本没有其他的经济来源,我们纯粹就是工薪阶层。那么,如何提高我们的薪水?这个话题大家一定会喜欢吧?

    为什么这里把月薪定义在30K,因为我觉得,30K是比较资深的工程师的合理薪酬,薪水再高的,估计一般都会有个经理什么的头衔了,就不能简单的算做是工程师了。

    老板不会无缘无故给我们加薪,但我们必须具备让老板给我们加薪的素质!

    那么,作为电源工程师的我们,需要什么样的素质呢?我们一起来讨论一下,好不好?我先说说个人的看法:

    1. 学历。我知道,有很多人认为,学历和能力并没有必然的联系。我也承认,的确有高分低能的现象存在。但我们不应该否认,经历过重重考试,闯关成功的高学历 者,大多数是聪明能干的。套用大学里老师教育我们的一句话:“如果连读书都读不好,你凭什么说你就能做好别的事?”在此,我丝毫没有看低低学历者的意思。因为有很多学历不高的人,并不是因为他们的智商,而是因为种种外部因素导致了学习的中断。但是我建议,如果你的学历不高,在有可能的前提下,尽量提高自己 的学历,最起码要提高的本科水平。在大学扩招的今天,说实话,本科学历,基本是成为一个工程师的起码要求了。当用人单位对你还不了解的时候,学历是最基本 的能够让你获得一个面试机会的钥匙。

    2. 做事就是做人,三思而后行。在日常的工作中,谦虚而好学,善于总结和积累,爱帮助别人,不摆架子,认真负责同时而不畏强权。一个事业成功的人,往往都是做 人成功的。一个人的力量毕竟有限,如果有大家的帮助,你的成长,包括薪水的成长,是很快的。很多高薪的工作,经常是朋友介绍或推荐而得到的。而你,如果希 望得到朋友的帮忙,首先必须成为一个让大家愿意接近的人。做一个智慧的人,不仅仅是聪明就够了的。

    3. 提升自己的知识技能。设计电源就像学围棋。入门容易,精通难。电源里面设计的知识面很宽广,那么我们就需要尽量多学各类知识。

    起码的:物理、高等数学、电磁学、电路分析等数学物理知识要会,再提升一些,例如自控原理、软件编程、数据结构、基础化学等要会一些。

    需要掌握一些专业的软件:

    ▪  电路设计类的,如protel、powerpcb等起码要会一种,越精通越好。

    ▪  机械设计类的,如ProE、Solidworks、AutoCad等起码要会一种,越精通越好。

    ▪  仿真类的,如Orcad/pspice、Saber、Matlab等会的越多越好、越精通越好。

    ▪  计算类的,如Mathcad,越精通越好。

    ▪  其它的,OFFICE系列是起码的。欢迎大家继续补充。

    ▪  还需要掌握:EMC、各国安全规范的标准和具体要求等。

    这些知识是互相交叉的,不是独立存在的。举例来说,一个优秀的电源工程师,肯定也是画电源PCB的高手,同时对安规和EMC的理解也应该是很深入的,那计算变压器、设计变压器结构、画各类图纸都应该不是问题。

    4. 要善于思考,勤于思考。思考技术问题,思考人生哲学。想想看,如果你从事的是靠低成本竞争的行业,那么你的薪水就是老板考虑的成本之一,那么你拿到高薪的 机会还会多吗?但这里,并不是要你好高骛远,有什么样的能力,你才能去做什么样的事。还是那句话,先让自己具备拿高薪的素质。

    看完文章有话说,欢迎留言聊聊职场那些坑!

    d3bc6ea0664fb1a941ba4a7dc370790a.pngbbd3a077e0e9eaa082149421505b3e93.png

    免责声明:本文系网络转载,版权归原作者所有。如本文所用视频、图片、文字如涉及作品版权问题,请在文末留言告知,我们将在第一时间处理!本文内容为原作者观点,并不代表本公众号赞同其观点和对其真实性负责。

    78d799a3624ac92fe40835b7b7885c1a.png 4013e7642c447ee3de1c09b866cc9be3.png

    —— The End ——

    2638fe9ba40dffa23877286a2ae0f903.png

    BUG很大,你忍一下


    9eaf0e66c6f3e5947362934835f42e76.png

    代码一键美化工具Astyle,非常实用


    701cd1220e4c43f70ab35c864bfb374b.png

    细节决定成败,聊聊防御性编程


    分享 💬  点赞 👍  在看 ❤️ 

    以“三连”行动支持优质内容!

    展开全文
  • UnQuote for Gmail-crx插件

    2021-04-03 17:28:08
    -您会看到以前的邮件中引用的文字不存在。 -它还可以保护签名并使其完整无缺。 -增加了对“全部答复”的支持。写答复时不要单击“ ...”,因为它会将引用的文本嵌入到答复区域中。 只需写您的回复即可忽略“ ...”...
  • 菜鸟独白很多小伙伴让我写Python进阶技巧的文章,其实Python的进阶我觉得主要对一些库的熟练使用,另外对代码的驾驭能力.个人觉得比较好的方法多看库,然后多读GitHub 上的源码,对你的进阶之路大有裨益!今天就来...

    菜鸟独白

    很多小伙伴让我写Python进阶技巧的文章,其实Python的进阶我觉得主要在对一些库的熟练使用,另外对代码的驾驭能力.个人觉得比较好的方法多看库,然后多读GitHub 上的源码,对你的进阶之路大有裨益!今天就来分享几个我平时非常喜欢的库,并详细举例说明,希望对大家有帮助!

    工具:Sublime Text

    语言:Python3.6

    高手必知的库:

    collections

    concurrent

    logging

    argparse

    我最喜欢的collections库

    大家知道Python里面的字典虽然好用,但是有两个显著的缺点,其中之一就是无序,如何在构造字典的时候,让字典里面填入的内容有序呢,一般的方法都是等字典的内容填充好了之后,用sorted排序,但是sorted,也并不能保证是按照添加的顺序进行迭代

    痛点1:字典无序的问题

    有没有办法让字典出生的时候就是带序的,有的就是collections库里面的OrderedDict,传统的字典输出的时候,有时会乱序

    image

    输出{'A': 0, 'B': 1, 'C': 2, 'E': 4, 'D': 3}

    如果我们想按照字典加入的顺序输出,必须用OrderedDict

    image

    OrderedDict会自动按照加入的顺序打印,但是这样做的坏处是开销很大,因为它内部维护了一张双向链表,大小是普通字典的2倍.

    痛点2:字典无缺省值的问题

    字典一般都是没有缺省值的,比如我们在爬虫的时候,我们希望我们爬取的关键字如果爬到有值则填入内容,如果没有则用缺省值代替.

    比如我前段时间做的年度电影榜单(2017年度电影榜单出炉),keys=['movie_name','movie_link','rating_num','rating_people_num']

    初始化这样的字典有三种方法:

    image

    但是上面3种解决方案有缺点:比如我们访问一个不存在的key的时候,如何让它返回一个缺省值 ?

    比如复杂一点数据结构,字典里面有列表,而不是一个简单的字符串?

    这些问题如何优雅的解决,用神器defaultdict

    比如我们构造一个学生的成绩单,缺省值我们认为是60分:

    image

    如果我们要获取一个不在名单里面的学生成绩

    print (students['sam'])

    输出60  #输出是60

    我们打印一些看看学生的成绩,是不是非常方便

    print (students)

    输出{'lili': 100, 'jack': 80, 'tom': 70, 'sam': 60})

    如果我们是一个字典嵌套集合的数据结构,我们只要把这个字典缺省设为set,然后只要管如何添加数据就行,不用操心如何初始化字典:

    image

    痛点3:像类一样玩转元组数据

    比如我们有一个数据结构students = (name, score, weight)

    我们要访问这个元组,需要通过下标去访问,非常不方便,如果这个元组很长,用下标会弄错,而且乱序之后不易扩展

    如果用一个类去构建,有点杀鸡用牛刀的赶脚!这个时候用namedtuple就有一种妙不可言的感觉,太方便了,可以体会一下Python之美.

    image

    然后我们访问这个属性,可以用类似类的访问属性方式去访问

    print (s1.name)

    print (s1.score)

    print (s1.weight)

    输出

    Leo

    100

    65

    简单而强大的并发库concurrent

    痛点4:如何简便的用并发

    我们在爬虫的时候,如果有100个url需要并发去爬取,一种通用的做法是开多线程,然后把100个url放入队列里面,开多线程从共享队列里面取url并发爬取,有没有更简便的方便,有的用concurrent库.

    比如:我们有一个需求是要爬取百度,头条,知乎,豆瓣,新浪和搜狐的首页.

    我们看用concurrent里面的线程池如何轻松解决

    image

    直接用ThreadPoolExecutor一个线程池的管理器来负责,thpool(max_workers=4)来创建一个线程池,你可以自己定义多个线程一起并发,然后用submit来往线程池里面添加task,是不是很简便!

    全能的日志库logging

    痛点5:日志怎么打才好

    在做大一点的项目的时候,有3个地方需要考虑:

    第一:代码架构的扩展性和维护性,主要会用一些设计模式来重构

    第二:代码的稳定性,会加很多异常保护

    第三:就是头疼的debug的日志,需求既要灵活,功能又要全面

    单一的print非常lower,为了解决这个痛点,我们必须用logging模块

    image

    这个时候我们去看一下mylog.log文件就会发现,里面把这5条信息都记录下来了

    CRITICAL:root:This is a critical message

    ERROR:root:This is an error message

    WARNING:root:This is a warning message

    INFO:root:This is a info message

    DEBUG:root:This is a debug message

    logging里面有5个级别critical>error>warning>info>debug

    debug是最低的,我们上面在basciConfig里面设置的是低优先级的DEBUG,如果我们改成WARNING,那么就只显示warning以上的级别(含warning)

    如果我们想输出的日志里面加时间戳,怎么办,简单的在basicConfig里面设置一下format格式就ok了

    %(levelname)s: 打印日志级别名称

    %(asctime)s: 打印日志的时间

    %(message)s: 打印日志信息

    image

    多面的命令行解析库

    痛点6:解决命令行解析多选项问题

    如果有做命令行的同学,或者是自动化脚本的对argparse一定不陌生,这个一个非常重要的库,可以对命令行提供强大的各种选项功能

    比如新建一个demo.py ,我们希望这个小脚本可以对两个数运算

    image

    我们在命令行下敲一下:

    xindeMacBook-Pro:HiPython xin$ python3 demo.py -h

    usage: demo.py [-h] [-t T] [-n1 N1] [-n2 N2]

    calculate two numbers

    optional arguments:

    -h, --help  show this help message and exit

    -t T        add/mul

    -n1 N1      First num

    -n2 N2      Second num-h立马就把各个选项的用法一目了然

    -t  表示你运算类型

    -n1表示第一个数

    -n2表示第二个数

    输入add作加法运算:

    xindeMacBook-Pro:HiPython xin$ python3 demo.py -t add -n1 10 -n2 20

    10.0+20.0=30.0

    输入mul作乘法运算:

    xindeMacBook-Pro:HiPython leoxin$ python3 demo.py -t mul -n1 10 -n2 20

    10.0*20.0=200.0

    结论:

    所有的高手都是从菜鸟一步一步走过来的,不断的吸取养分,保持如饥似渴的学习热情,多思考,总有一天菜鸟会展翅高飞成为一代高手! Python的实践性非常强,希望上面几个库可以给大家一些思路和参考,我们继续前行.

    作者:菜鸟学python

    链接:https://www.jianshu.com/p/5e0d5ca73e97

    展开全文
  • 初学必知的AIDL应用层上的Binder机制首先得理解几个概念:IPC:Inter-Process Communication,进程间的通信或跨进程通信。简单点理解,一个应用可以存在多个进程,但需要数据交换就必须用IPC;或者是二个应用...

    初学者必知的AIDL在应用层上的Binder机制


    首先得理解几个概念:

    IPC:Inter-Process Communication,进程间的通信或跨进程通信。简单点理解,一个应用可以存在多个进程,但需要数据交换就必须用IPC;或者是二个应用之间的数据交换。

    Binder:Binder是Android的一个类,它实现了IBinder接口。从IPC角度来说,Binder是Android中的一种跨进程通信方式。通过这个Binder对象,客户端就可以获取服务端提供的服务或数据,这里的服务包括普通服务和基于AIDL的服务。

    AIDL:Android Interface Definition language,它是一种Android内部进程通信接口的描述语言。


    一、AIDL的使用




    服务端:

    创建一个服务端工程,在工程中点击右键New->AIDL->AIDL File,默认直接点确定,这时会在工程中出现一个aidl文件:


    我们打开这个aidl文件,我们创建一个我们需要测试的方法:


    由于Android Studio是要手动编译才能生成对应AIDL的java文件,既然aidl文件是个接口,那就必须存在着实现这个接口的类,点击编译,系统自动生成一个java类,该java类的代码就是整个Binder机制的原理所在(会在下面第二步骤介绍原理):



    既然是个服务端,那么我们就要开始写服务了,创建一个类,继承Service:

    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    import android.os.RemoteException;
    import android.support.annotation.Nullable;
    import android.util.Log;
    
    import com.handsome.boke.IMyAidlInterface;
    
    public class MyService extends Service {
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return myS;
        }
    
        private IBinder myS = new IMyAidlInterface.Stub() {
    
            @Override
            public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
    
            }
    
            @Override
            public int add(int num1, int num2) throws RemoteException {
                Log.i("Hensen", "从客户端发来的AIDL请求:num1->" + num1 + "::num2->" + num2);
                return num1 + num2;
            }
        };
    }

    既然是个服务,就必须在manifests文件中配置:

    <!--exported:允许外界访问该服务,AIDL必备条件-->
            <service
                android:name=".Aidl.MyService"
                android:exported="true"/>
    到现在服务端写好了,开启模拟器 启动这个程序 ,记得在代码中开启服务:

    public class LoginActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_login);
    
            startService(new Intent(this, MyService.class));
        }
    }


    客户端:


    在工程中点击右键New->Module,按默认确定,finish:


    关键的一步来了,
    复制服务端的aidl整个文件夹(包括里面的包、aidl文件、完整无缺)粘贴到客户端对应放aidl的地方


    不要忘了,客户端还要
    手动编译


    好了我们来写客户端的代码(我们在MainActivity中放一个”AIDL“的按钮,先绑定服务,然后点击按钮调用):

    public class MainActivity extends AppCompatActivity {
    
        IMyAidlInterface iMyAidlInterface;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            //绑定服务
            Intent intent = new Intent();
            intent.setComponent(new ComponentName("com.handsome.boke", "com.handsome.boke.Aidl.MyService"));
            bindService(intent, conn, BIND_AUTO_CREATE);
        }
    
        /**
         * 点击“AIDL”按钮事件
         *
         * @param view
         */
        public void add(View view) {
            try {
                int res = iMyAidlInterface.add(1, 2);
                Log.i("Hensen", "从服务端调用成功的结果:" + res);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 服务回调方法
         */
        private ServiceConnection conn = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                iMyAidlInterface = null;
            }
        };
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            //解绑服务,回收资源
            unbindService(conn);
        }
    }


    测试结果(先开启服务端,开启服务后,接着开启客户端,绑定远程服务):

    08-19 10:59:34.548 6311-6328/com.handsome.boke I/Hensen: 从客户端发来的AIDL请求:num1->1::num2->2
    08-19 10:59:34.550 7052-7052/com.handsome.app2 I/Hensen: 从服务端调用成功的结果:3

    二、AIDL的Binder机制原理分析



    分析原理:

    /*
     * This file is auto-generated.  DO NOT MODIFY.
     * Original file: D:\\workspace5\\Boke\\app\\src\\main\\aidl\\com\\handsome\\boke\\IMyAidlInterface.aidl
     */
    package com.handsome.boke;
    // Declare any non-default types here with import statements
    
    public interface IMyAidlInterface extends android.os.IInterface {
        /**
         * Local-side IPC implementation stub class.
         */
        public static abstract class Stub extends android.os.Binder implements com.handsome.boke.IMyAidlInterface {
            private static final java.lang.String DESCRIPTOR = "com.handsome.boke.IMyAidlInterface";
    
            /**
             * Construct the stub at attach it to the interface.
             */
            public Stub() {
                this.attachInterface(this, DESCRIPTOR);
            }
    
            /**
             * Cast an IBinder object into an com.handsome.boke.IMyAidlInterface interface,
             * generating a proxy if needed.
             */
            public static com.handsome.boke.IMyAidlInterface asInterface(android.os.IBinder obj) {
                if ((obj == null)) {
                    return null;
                }
                android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
                if (((iin != null) && (iin instanceof com.handsome.boke.IMyAidlInterface))) {
                    return ((com.handsome.boke.IMyAidlInterface) iin);
                }
                return new com.handsome.boke.IMyAidlInterface.Stub.Proxy(obj);
            }
    
            @Override
            public android.os.IBinder asBinder() {
                return this;
            }
    
            @Override
            public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
                switch (code) {
                    case INTERFACE_TRANSACTION: {
                        reply.writeString(DESCRIPTOR);
                        return true;
                    }
                    case TRANSACTION_basicTypes: {
                        data.enforceInterface(DESCRIPTOR);
                        int _arg0;
                        _arg0 = data.readInt();
                        long _arg1;
                        _arg1 = data.readLong();
                        boolean _arg2;
                        _arg2 = (0 != data.readInt());
                        float _arg3;
                        _arg3 = data.readFloat();
                        double _arg4;
                        _arg4 = data.readDouble();
                        java.lang.String _arg5;
                        _arg5 = data.readString();
                        this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
                        reply.writeNoException();
                        return true;
                    }
                    case TRANSACTION_add: {
                        data.enforceInterface(DESCRIPTOR);
                        int _arg0;
                        _arg0 = data.readInt();
                        int _arg1;
                        _arg1 = data.readInt();
                        int _result = this.add(_arg0, _arg1);
                        reply.writeNoException();
                        reply.writeInt(_result);
                        return true;
                    }
                }
                return super.onTransact(code, data, reply, flags);
            }
    
            private static class Proxy implements com.handsome.boke.IMyAidlInterface {
                private android.os.IBinder mRemote;
    
                Proxy(android.os.IBinder remote) {
                    mRemote = remote;
                }
    
                @Override
                public android.os.IBinder asBinder() {
                    return mRemote;
                }
    
                public java.lang.String getInterfaceDescriptor() {
                    return DESCRIPTOR;
                }
    
                /**
                 * Demonstrates some basic types that you can use as parameters
                 * and return values in AIDL.
                 */
                @Override
                public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        _data.writeInt(anInt);
                        _data.writeLong(aLong);
                        _data.writeInt(((aBoolean) ? (1) : (0)));
                        _data.writeFloat(aFloat);
                        _data.writeDouble(aDouble);
                        _data.writeString(aString);
                        mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
                        _reply.readException();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                }
    
                @Override
                public int add(int num1, int num2) throws android.os.RemoteException {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    int _result;
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        _data.writeInt(num1);
                        _data.writeInt(num2);
                        mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
                        _reply.readException();
                        _result = _reply.readInt();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                    return _result;
                }
            }
    
            static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
            static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
        }
    
        /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
    
        public int add(int num1, int num2) throws android.os.RemoteException;
    }
    


    我们来分析一下这个类

    首先本身继承Iinterface,所以他也是个接口,接口中必须有方法,代码定位到结尾有2个方法。

    public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
        public int add(int num1, int num2) throws android.os.RemoteException;
    这两个方法就是basicTypes和add,就是我们服务端的2个方法。

    接着发现该接口中有1个内部类Stub,继承自本身(IMyAidlInterface)接口,代码定位到Stub类。

    这个Stub有个构造方法、asInterface、asBinder、onTransact(先不介绍)。

    接着发现该内部类Stub还有一个内部类,代码定位到Proxy(我们把它称为代理)类,也是继承自本身(IMyAidlInterface)接口,所以实现该接口的两个方法。

    /**
                 * Demonstrates some basic types that you can use as parameters
                 * and return values in AIDL.
                 */
                @Override
                public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        _data.writeInt(anInt);
                        _data.writeLong(aLong);
                        _data.writeInt(((aBoolean) ? (1) : (0)));
                        _data.writeFloat(aFloat);
                        _data.writeDouble(aDouble);
                        _data.writeString(aString);
                        mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
                        _reply.readException();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                }
    
                @Override
                public int add(int num1, int num2) throws android.os.RemoteException {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    int _result;
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        _data.writeInt(num1);
                        _data.writeInt(num2);
                        mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
                        _reply.readException();
                        _result = _reply.readInt();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                    return _result;
                }
            }
    在这个类里面我们会发现有2个标识:用来区分两个方法,到底你远程请求哪个方法的唯一标识, 代码定位到代理类的结尾

     static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
            static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    回过头来,还记得我们客户端做了什么吗?答案:绑定一个服务,在回调方法获取一个接口(iMyAidlInterface),它是 直接静态使用IMyAidlInterface里面的静态类Stub的asInterface的方法 :(好了我们去跟踪到Stub类asInterface这个方法)

     /**
         * 服务回调方法
         */
        private ServiceConnection conn = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                iMyAidlInterface = null;
            }
        };
    代码定位到Stub类asInterface方法

    public static com.handsome.boke.IMyAidlInterface asInterface(android.os.IBinder obj) {
                if ((obj == null)) {
                    return null;
                }
                android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
                if (((iin != null) && (iin instanceof com.handsome.boke.IMyAidlInterface))) {
                    return ((com.handsome.boke.IMyAidlInterface) iin);
                }
                return new com.handsome.boke.IMyAidlInterface.Stub.Proxy(obj);
            }
    前面只是做一些判断、 看一下最后一句话 :我们将传过来的obj还是传给了它的 代理类 来处理, 返回的是代理类的对象

    return new com.handsome.boke.IMyAidlInterface.Stub.Proxy(obj);
    所以在客户端的iMyAidlInterface = ……,则是拿到它的 代理类,好了,这个时候就看客户端调用代理类干嘛了

    int res = iMyAidlInterface.add(1, 2);
    他调用了代理类的add方法, 代码定位到代理类的add方法
    @Override
                public int add(int num1, int num2) throws android.os.RemoteException {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    int _result;
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        _data.writeInt(num1);
                        _data.writeInt(num2);
                        mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
                        _reply.readException();
                        _result = _reply.readInt();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                    return _result;
                }
    你会发现,它把数据写进了_data里面,最后调用 transact方法 ,传入_data数据,唯一标识Stub.TRANSACTION_add。

    mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
    然后这个transact方法就是通过底层了,通过底层结束后,这些参数送到哪了?答案:底层会走到stub类中的 onTransact方法,通过判断唯一标识,确定方法:
    case TRANSACTION_add: {
                        data.enforceInterface(DESCRIPTOR);
                        int _arg0;
                        _arg0 = data.readInt();
                        int _arg1;
                        _arg1 = data.readInt();
                        int _result = this.add(_arg0, _arg1);
                        reply.writeNoException();
                        reply.writeInt(_result);
                        return true;
                    }
    在这个地方将传过来的参数解包,readInt方法。然后调用 this.add 方法,this指的就是服务端,调用 服务端 的add的方法:

    int _result = this.add(_arg0, _arg1);
    将得到的结果,写入 reply

    reply.writeNoException();
                        reply.writeInt(_result);
    最后一句话,最后返回系统的 ontransact 方法,传入结果reply:

    return super.onTransact(code, data, reply, flags);
    所以我们在上面获得的结果就是reply(答案:3):

    int res = iMyAidlInterface.add(1, 2);

    最后总结下整个过程



    三、AIDL编写时候的一些错误

    错误一:

    Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'int com.handsome.boke.IMyAidlInterface.add(int, int)' on a null object reference
    这个错误很有可能是你写的服务端,忘记返回myS了,返回的是个null

    @Override
        public IBinder onBind(Intent intent) {
            return null;
        }

    错误二:


     Caused by: java.lang.SecurityException: Not allowed to bind to service Intent { cmp=com.handsome.boke/.Aidl.MyService }
    这个错误很有可能是的服务端在manifests文件中少了exported="true"的属性

    <!--exported:允许外界访问该服务,AIDL必备条件-->
            <service
                android:name=".Aidl.MyService"/>














    展开全文
  • 不存在放之四海皆准的法则,但特定情况下,某些观点会更接近真实。这一节,我要提出这个观点:现阶段的学校数学没有正确反映数学的本质。 Conceptual systems can be broadly classified as being either ...
  • 向上生长,向下兼容

    千次阅读 2021-09-14 00:17:38
    插个图片,昨天取关559,是新高,是真取关,不存在所谓的以取关噱头的营销手段。之前也有取关小高潮,嗯,之前也经常劝退来着,是真劝退,我嫌订阅的人多行不行,我就想能能降下来行不行。 我知道很多读者...
  • 文/光剑白居易《暮江吟》云:“可怜九月初三夜,露似真珠月似弓。”辛丑年寒露节气,正好是阴历九月初三。《月令七十二候集解》说:“九月节,露气寒冷,将凝结也。”寒露节气,大雁南飞,菊始...“审复何以永日...
  • 自己还一个某一个位置原地踏步,想变得有钱,有能力,却知道努力方向,也知道怎么做。或者说愿意吃苦,愿意受累,又想享受。然后情 绪就会变成对社会的仇恨跟抱怨。当所有的原因归因到自己身上,是能力,...
  • 从我们的测试中,从Ubuntu 10.10更改Xubuntu 10.10,要求我们下载完整Xubuntu文件的到一半(42%)。 Kubuntu live desktop (with installer) x86 Kubuntu实时桌面(带有安装程序)x86 Note: Kubuntu is only ...
  • 简单点理解,一个应用可以存在多个进程,但需要数据交换就必须用IPC;或者是二个应用之间的数据交换。Binder:Binder是Android的一个类,它实现了IBinder接口。从IPC角度来说,Binder是Android中的一种跨进程通信...
  • 大家知道Python里面的字典虽然好用,但是有两个显著的缺点,其中之一就是无序,如何构造字典的时候,让字典里面填入的内容有序呢,一般的方法都是等字典的内容填充好了之后,用sorted排序,但是...
  • 作者丽萨·克龙(Lisa Cron),现任加州大学洛杉矶分校写作项目的老师,她毕业于加州大学伯克利分校,出版业、电视业工作多年,也是纽约华纳兄弟电影公司、洛杉矶威秀电影公司等的故事顾问。擅于写故事,尤其擅于...
  • 审稿审什么你真的弄清楚了吗
  • .any——or,只要有一个true,输出就是true np.isinf(data).any() = False——没有无穷值 all——and,所有true输出才是true np.isfinite(data).all() = True——没有无穷值 查看缺省值 np.isnan(data).any...
  • 以后天八卦例来分析aaas作为组织的数据功能和运行原理--4种结构规则(数据结构)和三个运行时(数据动态链接)部分。
  • 第一次接收到此流时,将缓冲区转换图像之前,我能够一次读取16位流,以便对每个像素执行一些计算,即每个像素存在16位数据块.现在下半部分是Django网络应用程序,这次我也通过ffmpeg,nginx,hls流向您展示了此视频输出...
  • 题目:渠道客户通过有意或无意的市场行为所触发的存在于公司营销渠道系统外部及内部的各种矛盾,称为( ) 题目:一般言,制造商会依据渠道客户的盈利能力、企业对于渠道客户控制的可能性和渠道客户的适应性三项...
  • 我的就是: 要是以后遇到这样的问题,先尝试一下各种可能之后,再不行就上网查,注意一定要保证输入格式(有无缺空格,缺斜杠的等,还有目录名称的大小写...) 三:第一次linux下写C语言代码: 好了,问题解决...
  • 豌豆荚融合SDK接入常见问题注意:1、如您的游戏豌豆荚平台上过线,则需要接入豌豆荚融合SDK提审豌豆荚包;新游无需接入豌豆荚融合SDK。具体可直接从游戏提包页面查看是否有提豌豆荚包入口,有则需要接豌豆荚SDK。2...
  • 通常,对于每个归档对象元数据管理器中出现一个外部文件表项(entry),对于每个外部文件表项可以有很多内部文件表项。通常,内部文件布局取决于系统。给定的实施中,盘上的该数据的实际物理格式被存储于一系列...
  • 许多初学用户已经问我们WordPress如何存储图像,以及他们可以做什么来更有效地组织媒体库。 本文中,我们将说明WordPress如何您的网站上存储图像。 WordPress如何存储图像? (How Does WordPress Store ...
  • 表中设置了id字段,该字段UNIQUE属性,当插入的id已存在时引发冲突。 引发冲突后insert会做一些处理,处理方式由OR字句定义。包含如下: ROLLBACK当发生约束冲突,立即ROLLBACK,即结束当前事务处理,命令中止并...
  • 元素周期表是根据什么排列的?

    千次阅读 2021-02-05 05:27:01
    展开全部元素周期表是元素周期律用表格表达的具体形式,它反映元素原子的内62616964757a686964616fe78988e69d8331333231613932部结构和它们...元素周期表中的位置能反映该元素的原子结构。周期表中同一横列元素...
  • 利用备用Mac的一种方法是...尽管娱乐界正在通过以Netflix,Disney +和Apple TV +之类的服务转向以流媒体中心的存在,但并非所有内容都可以这些服务上查看。您可能光盘上拥有一些内容,这些内容根本无法通过流媒体
  • 逐项求导的坑,祸害

    千次阅读 2020-12-24 15:09:05
    为了能够更好地帮助大家理解何为幂级数的和函数,小编本文将结合一道考研数学真题来讲述。1.幂级数和函数考研真题下面这道题是2016年考研数学三真题:小编对真题稍加修改,大家看看是否会影响解题过程和步骤。可能...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,657
精华内容 662
关键字:

为什么存在者存在而无却不在