2016年都結束了,美國權威機構公布最安全SUV車型

98萬起,而且使用的還只是6AT變速箱,相對於競爭對手來說呈劣勢。奧迪Q5今年奧迪推出的產品都可以說是更為精練了,性能增進不少,質量下降不少,最為重要的是油耗可以降低到的一個新的層次。不過就是這幅外觀不少人覺得不夠以前“霸氣”,這樣的外觀評價就看個人喜好了。

前言

SUV市場絕對是近些年最發展最為迅猛的市場,想起SUV初期的時候,SUV因為高重心以及比較一般的性能,在安全性能方面由其是抗側傾能力是非常差的,事故率要比起轎車還要高。而經過這麼多年的發展,SUV安全性能終於有着質的提升,而今年或者最高安全評定的SUV已經不比轎車少了,那麼有哪些車型能夠上榜呢?

三菱歐藍德

歐藍德在性能上表現始終是中規中矩,沒有太多的特色,2.0L以及2.4L自然發動機配合起CVT變速箱,動力是白開水般平淡,不過勝在歐藍德價格較低而且還有着7座布局,所以性價比不俗。

日產奇駿

日產奇駿一改上一代的硬派路線,成為了更為稱職的城市SUV,有着不錯的燃油經濟性以及較大的空間表現,所以在合資SUV中銷量都是排在前列。國外新款已經上市,想要購買的不妨等一下外觀更漂亮的新款。

斯巴魯森林人

斯巴魯一直在我國都是比較低調的,這款森林人也是如此,作為頂配還有着2.0T的發動機總成,雖然配搭CVT變速箱,但是斯巴魯一貫的高素質底盤使得它還是有着不少的駕駛樂趣,但價格已經到達33.48萬之高。

豐田RAV4

豐田造車的一貫標準就是“均衡”,這款緊湊型SUV雖然沒有什麼特出的地方,但是卻是最讓人喜歡的,中上水平的空間動力,不俗的油耗以及超低的故障率,使得它的銷量並不低。

而且改款后外觀極為動感。

現代勝達

勝達雖然售價不算低,但是卻是一款有着高顏值的中型SUV,不過軸距卻是比較的“緊湊型”,空間表現尚可,但是對於7座車型來說就相對局促,所以我們推薦的是5座版本,而且是2.0T的版本,動力更強油耗更低。

謳歌RDX

謳歌是本田推出的高端品牌,但是低調程度卻是比起英菲尼迪以及雷克薩斯都要低調。不過競爭力確實是比較一般,RDX售價高達39.98萬起,而且使用的還只是6AT變速箱,相對於競爭對手來說呈劣勢。

奧迪Q5

今年奧迪推出的產品都可以說是更為精練了,性能增進不少,質量下降不少,最為重要的是油耗可以降低到的一個新的層次。不過就是這幅外觀不少人覺得不夠以前“霸氣”,這樣的外觀評價就看個人喜好了。

別克昂科威

昂科威絕對是逆襲的典範,是由國內主導研發,是中國特供車,然而卻被反銷回美國老家。舒適性極佳,而且內飾以及隔音水平高。加上這安全性能,足以表明我國研發實力還是可以的。

雷克薩斯NX

雷克薩斯NX可以說是雷克薩斯最受歡迎的SUV系列,外觀靚麗,而且油耗表現優秀,更為關鍵的是有着混動車型,故障率以及油耗的優異成績就足以打敗不少競爭對手。

雷克薩斯RX

雷克薩斯RX絕對是霸氣的一款SUV,中大型SUV加上極具進攻性的前臉,看起來非常兇狠,難怪不少人說它能“嚇哭小朋友”。但實際駕駛感受卻是非常輕巧易於操控,這是豐田的一貫調校風格。

奔馳GLE

奔馳的產品一向是高質量的,而這款GLE也是如此,中大型SUV的車身尺寸使得它在空間表現上相當優秀。3.0T以及4.0T的動力絕對不止是充沛,不過這樣也使得價格相當高,足足要77.80萬起售。

沃爾沃XC60

在被吉利收購以後,還能保持這樣的研發能力,是相當令人意外的一件事。在主動安全領域方面,沃爾沃始終都是走在了前列位置。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

※教你寫出一流的銷售文案?

※超省錢租車方案

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※回頭車貨運收費標準

網友最喜愛的車型竟是他們!為此教授操碎了心…

而這一位是屬於玩車TV上的朋友,拿到了1312的點贊也是小米MAX的獲得者之一,到截稿日止,獲知他已經收到了玩車TV送出的小米MAX。這一條評論也反應出他對GS8的喜愛,相信這也是眾多粉絲的心聲,頂國產車這一類的評論點贊數一般不會差的。

“為粉絲服務”是一直以來的宗旨!從玩車創辦至今,我們已經回答了無數粉絲關於購車的問題。通過每天與粉絲的互動,我們都會篩選出你們最為關注的汽車問題。通過推送的文章形式,助你們解決購車、用車方面的問題,這是日常的工作。

為了讓粉絲們更了解“玩車”,先給你們說說的基本資料,2014年5月“玩車”正式創辦,到現在旗下已經擁有三大公眾號平台,玩車、車買買、玩車TV,三個大號在微信後台端的粉絲數量已經突破800W!這是一個非常龐大的群體,而每天都會有專人去跟進你們寫下的評論,在這兒也希望你們能夠多給提供一些營養的評論,這對於的工作有着深刻的意義。了解粉絲們的需求,就能針對你們的喜好作出一定的內容調整,務求解決你們的購車、用車問題。

廣州車展在上上周日已經完美謝幕,記得在車展期間在“玩車”“車買買”“玩車TV”聯合舉辦了一個“2016我就喜歡的汽車”年度車型評選投票的活動!評論點贊數最多的前10位也將獲得送出的豐厚大獎!經過4天的角逐也選出了前10名的點贊數最高的消費者。

注:圖中僅為部分獎品

的豐厚的禮品已經在快遞的路上,請各位得獎者注意一下快遞哥哥的電話。

以上這些消費者,就是本次獲獎的名單,在這裡在此衷心感謝你們的支持。值得一說的是!這一類的活動將會不定期舉辦,所以你參加了就會有獲獎的機會,也希望你們能夠踴躍參与。舉辦這一類的活動,其實初衷很簡單!那就是讓你們能肯定的工作,通過這樣生動有趣而且有獎品的形式來給大家帶來相關的車型對比,能夠讓你們更好地了解車型的狀況。另外在評論區寫下自己的想法、觀點,寫下你們在用車方面出現的問題,也能讓更好地了解你們,幫助你們解決問題。

來看看精選評論中的精品!

這一次獲獎的朋友一樣,為什麼發的評論都有那麼多的點贊數支持?在看來主要原因有兩個:第一個是身邊不少的朋友的支持;第二個因為評論能夠引起眾多粉絲的認可!

這一位評論十分用心的朋友,連都忍不住為他點贊!他按車型羅列出自己的看法,而且還別出心裁進行了評星,看得出對車型的調性很熟悉。儘管沒拿到第一名,但是這段文字句句是乾貨,形式新穎,讓眼前一亮。

這是出自車買買平台上的冠軍,1827贊也是三個平台之中最高的。看看評論能看出這一位粉絲是一個“本田黨”。從評論中也反映出這位消費者對思域的高度熱愛,另外這位粉絲應該對汽車賽事比較關注。的粉絲中“本田黨”可不少!得到這麼多的支持也是很正常的。

而這一位是屬於玩車TV上的朋友,拿到了1312的點贊也是小米MAX的獲得者之一,到截稿日止,獲知他已經收到了玩車TV送出的小米MAX。這一條評論也反應出他對GS8的喜愛,相信這也是眾多粉絲的心聲,頂國產車這一類的評論點贊數一般不會差的。

16年粉絲最喜歡的新車與購車趨勢!

在轎車方面,最受歡迎的車型是全新奧迪A4L。說實話,基於奔馳在最近半年的強勢表現,奔馳E級作為C級車能有這樣的群眾基礎已經很優秀,E級有這樣的表現非常符合的預期。特別是A4L,我們看到不少粉絲提到了電視劇《奮鬥》中陸濤那輛A4給他留下的深刻印象,可見奧迪在中國市場多年的深耕,其它品牌是無法在短時間超越的。

再來談談新A4L的產品力。新款A4L在整體的車身線條上變動並不大,新款的前進氣格柵、前後大燈、輪圈造型都作出了明顯的改動,但是認為A4L之所以受歡迎大多是因為它比老款的軸距長了39mm。在我國有一個很奇怪的現象,豪華車也一樣,只要加長了軸距,銷量就會暴增。另外A4L受歡迎是有理由的!1、奧迪車標倍有面子;2、長軸距空間更大、外觀看起來更長顯大氣;3、28.99-41.28萬的售價配上大幅度的優惠,在終端售價方面並不高;

在SUV方面,奪冠的依舊是傳祺的GS8,這也是預料之內的事情。GS8真的是太火了,火到發紫!它擁有一副非常大氣而且原創的外觀設計、一個碩大的車身尺寸、大7座SUV、高於同級的配置水平、2.0T+6AT的動力總成,關鍵是售價也不算高。在看來這車真的像是看着消費者的口味而打造,然而這車由於購買人數太多,已經處於一車難求的狀況。

從數據表上,我們可以看出我國消費者的選車喜好。目前大部分的消費者更關注SUV車型!首先SUV車型普遍底盤更高,在通過性方面會比轎車更好,這是眾多消費者所看重的;在尺寸相差不大的情況下,SUV車型看起來比轎車更上檔次;由於車身的設計原因,在內部空間方面SUV比轎車更大;絕大多數的廠家都開始主力研發“SUV”車型,所以在市面上SUV車型的選擇性更高!轎車車型開始出現滯后發展的情況;綜合SUV所有的優點,你能發現目前消費者在購車時所關注點是:品牌、SUV、尺寸大、外觀大氣、空間大、配置高,這也是未來中國汽車發展的大趨勢。

一直在努力幫助粉絲購車,因此在玩車、車買買及玩車TV三大號上聚集了大量購車用戶,這次跨號舉辦的評選活動,客觀反映了消費者購車的關注方向,映射出中國車市接下來的半年甚至一年,消費趨勢的大方向!接下來也將舉辦更多的互動活動,記住,天天見哦。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※別再煩惱如何寫文案,掌握八大原則!

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※超省錢租車方案

※教你寫出一流的銷售文案?

網頁設計最專業,超強功能平台可客製化

※產品缺大量曝光嗎?你需要的是一流包裝設計!

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

有錢又長得帥的人開什麼車?

與客戶在車上聊天時就更贊了,兩個座位向中間移動靠在一起,距離近了合同還會遠嗎。更別說奧德賽還有電動側滑門,還是全系標配。老人、小孩、女士上下車不用費力的推拉門,迎接客戶上車時自動門也是一種禮遇。更人性化的是,奧德賽的車門離地很低,低到什麼程度呢。

在“洪荒之力”、“藍瘦香菇”后,最近不免又被一句廣告語洗腦:有錢還得長得帥,出門才開奧德賽。

這句話出自馬東的新節目《飯局的誘惑》,節目雲集眾多明星,拼情商拼智商拼口才,可謂金句與笑料齊飛。更好玩的是《奇葩說》之後,馬東的花式口播功力依舊強勁。奧德賽作為贊助商之一,在節目里狂刷存在感,每次植入,彈幕就一片6到飛起,就像下面這樣:

以致於奧德賽最近簡直火遍大江南北,因此叫獸覺得有必要來說說這輛車。

MpV的英文全稱為Multi-purpose Vehicle,翻譯過來就是多用途汽車。多用途就意味着它涵蓋了轎車、SUV、旅行車等車型的功能,是用車需求升級后的不二之選,所以成為了很多人的“人生第二輛車”。而自1994年就在日本誕生,2002年進入中國至今已有14年,車型也更新到了第五代的奧德賽,無疑是如今最熱門的MpV之一。

可以這麼說,當你想要購買一輛MpV時,奧德賽總是繞不開的選擇。

其實“有錢又得長得帥,出門才開奧德賽”這句話不僅是對奧德賽目標人群形象貼切的刻畫,也是對奧德賽最“耿直”描述了。有錢長得帥背後,可以想象成一位事業有成,內心穩重的男士,那與之相配的奧德賽,想然也是一輛有顏值也有內涵的座駕。

不同於其他過於華麗或過於方正的MpV設計,奧德賽的外觀給人協調、精緻的感覺。仔細看就能發現其中的巧妙。前臉寬大的鍍鉻和上挑的LED大燈帶出氣勢后,側面上下雙腰線勾勒出立體的動感,而不是採用像其他車型那般橫貫車身的凌厲腰線,這樣一來奧德賽的外形就不會讓人覺得“高冷”,反而顯得大氣不失格調。尾部也是這種“一放一收”式的設計,方正凸顯穩重,但橫向貫穿的鍍鉻和光帶式的尾燈又帶出時尚與豪華。這樣穩重不失格調的外形,恰恰既能滿足商業精英出席各種正式場合,也適合充滿活力的家庭。因此奧德賽也有“宜商宜家”的稱號。

顏值高是一方面,內在更是奧德賽屹立MpV市場前列多年的重要原因。畢竟第一代奧德賽問世時,就是以打破傳統轎車束縛,能提供7人舒適乘坐的優勢獲得了人們的青睞。

當遇上三排座位的車時,很多人都有這樣的苦惱:用什麼樣的姿勢坐進第三排才能展現我的優雅與帥氣?坐奧德賽就可以免去這樣的擔憂,車內是2+2+3的布局,這樣的安排讓二排更加寬敞舒適不說,通過中間過道就能輕鬆坐到第三排,在車裡簡直能像在家裡一般自在行走。當家人之間交談時,二排座椅前後左右移動一下,就能讓彼此靠得更近。與客戶在車上聊天時就更贊了,兩個座位向中間移動靠在一起,距離近了合同還會遠嗎?

更別說奧德賽還有電動側滑門,還是全系標配。老人、小孩、女士上下車不用費力的推拉門,迎接客戶上車時自動門也是一種禮遇。更人性化的是,奧德賽的車門離地很低,低到什麼程度呢?上下車就像踏一級台階這麼簡單,對穿裙子的女士來說是最刷好感的。

坐車,誰都希望能夠像坐在家裡沙发上一樣自在,這就要專門說說奧德賽第二排堪比航空頭等艙的座椅了,簡直是為了實現人們這樣的願望而來。柔軟且包裹性強,帶頭枕和腳托,椅背最大程度往後調後人幾乎能以平躺的姿勢攤在座椅上。這時候再打開頭頂上的屏幕,拿起遙控器播放一期《飯局的誘惑》或者追最新一集《The Walking Dead》,完美Cos葛大爺,從此別問為什麼很多人到家不願下車,等看完這一集再說!

擁有一輛這樣又舒服又寬敞的奧德賽,節假日必定閑不住。元旦節馬上到了,老爸帶全家去郊外釣個魚,開啟超大模式,釣魚竿、帳篷、吃的喝的儘管往車上裝。周末是老媽的購物時間,開啟休閑模式就足夠裝下大包小包了。公司偶爾有物料要運,比如燈具或者長木板,超長模式的奧德賽已經standby了。空間想怎麼變就怎麼變,簡直是居家辦公好幫手。

這時候有人就要說了,前面說的都是坐車的事兒,可這麼大的車,好不好開啊?別擔心,有科技來幫忙。走在擁擠的城市主幹道,想看看後方的車是不是貼得太近,打開360°全景影像就能完美掌握路況。轉彎或車速比較高時,盲區檢測系統時刻幫你注意着左右車輛。老媽購物回家發現停車位有點窄,那就用自動泊車吧,完美。

看完這樣的奧德賽我們再看如今市面上很多車型,為了迎合市場,紛紛把各種元素不斷往車上堆砌再冠以豪華的名號,但這麼做可能過猶不及。其實像奧德賽這樣,多從每個人用車的角度考慮,車門高度降低一點,開門的方式簡單一點,乘坐起來更舒服一點,空間大一點再大一點,駕駛簡單一點,每個配置都能用到一點,把每個“一點”做到極致,才是真正的做加法,最終虜獲大家的心。

內外兼修,宜商宜家,作為“有錢又長得帥”人士的座駕,這就是奧德賽的自我修養。它能完美連接工作與生活,所以當你考慮入手一輛MpV時,奧德賽是很不錯的選擇。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※教你寫出一流的銷售文案?

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※回頭車貨運收費標準

※別再煩惱如何寫文案,掌握八大原則!

※超省錢租車方案

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※推薦台中搬家公司優質服務,可到府估價

聽說這是老闆最愛的車?教授試過之後告訴你逼格有多高

配置方面,發動機啟停、自動駐車、陡坡緩降和車身穩定系統都一應俱全,同時娛樂功能也十分豐富,帶4G功能的安吉星系統、Carplay手機互聯繫統都有配備。值得一提的是新一代GL8還配備了12揚聲器的BOSE高級音響,娛樂功能也毫不含糊。

活躍於國內MpV市場的車型有很多,能取得一席之地的也不少,小至五六萬,大至上百萬,各價位都有不少優秀的MpV,但真正能被稱為經典的不多,而合資品牌MpV的銷量王,別克GL8就是其中一款。新一代GL8已經於11月5日上市,算上Avenir版本的話共有五個車型,售價區間為28.99-44.99萬元。

新一代GL8搭載了全新的2.0T發動機,同時外觀、內飾和科技配置都迎來升級。這款在國內吸引了眾多老闆級消費者的MpV其換代車型到底有啥本事?親身試駕了GL8 Avenir,一起來看看這輛豪華MpV吧。

外觀:精緻、時尚,豪華感更強了

上一代GL8的外觀雖然也不會很老土,但是整體的感覺還是偏向於一輛兢兢業業的把乘客從A點運送到B點的MpV,而新一代的GL8,在維持作為MpV外型穩重的同時豪華感明顯更強了。

前臉採用了全新的翼展式中網,觀感更加開揚大氣,GL8 Avenir更採用了類似盔甲造型的進氣格柵,與底部橫條狀的格柵相互呼應,搭配鍍鉻飾條的裝飾,時尚大氣又透露出豪華感。

大燈採用了全LED的光源,秀氣的造型與中網延伸過來的線條相融合,前臉的整體感十足。

新一代GL8的側面輪廓並沒有大改,但從上下邊緣的銀色裝飾、一體式的車門外拉手、懸浮式的車頂以及前門左下方的“Avneir”標誌可以看出別克的新GL8在側面設計上也花了不少功夫,得到的結果就是GL8的檔次感明顯的提高了。

你看到的這個炫酷的皇冠造型18寸輪轂是Avenir車型獨有的,其他車型都採用17寸輪轂,Avenir的輪胎是馬牌pROCONTACT系列的靜音輪胎,其他車型則為CC6系列輪胎,規格有所不同。

從外觀可以看出新一代GL8已經從以往的一輛兢兢業業的運輸工具進化成一個能夠營造出豪華氛圍的商務MpV,也相信這會是MpV發展的一個趨勢,而GL8已經走在了前方。

內飾:主題依舊是豪華

中控台採用了對稱式的布局,上方的皮質包裹和啞光木質飾板也是Avneir區別於普通車型的標誌之一。副駕前方和門板的木質飾板上還加入了類似菱形小方塊組成的雕刻裝飾,也是Avenir的特徵。

座椅方面,GL8 Avenir使用了“全粒面”級別的公牛皮作為面料,而且採用了繁瑣的製作工藝,觸感很細膩。同時填充方面採用了軟硬適中的物料,因為廠家相信太過柔軟的座椅不利於長期乘坐,試乘之後覺得這的確不無道理。

細心的人可能已經發現新一代GL8的空調控制區域為觸控板的設計,科技感十足,但是觸控靈敏度的確不如物理按鍵,但好在空調的調整已經集成到了中控屏,調節起來十分方便。

配置方面,發動機啟停、自動駐車、陡坡緩降和車身穩定系統都一應俱全,同時娛樂功能也十分豐富,帶4G功能的安吉星系統、Carplay手機互聯繫統都有配備。值得一提的是新一代GL8還配備了12揚聲器的BOSE高級音響,娛樂功能也毫不含糊。

空間:讓你真正感到你就是老闆

對於一輛MpV來說,其精髓在於第二排座椅的乘坐舒適性,前面已經提到其座椅面料和填充的厚實程度已經進行了優化,所以關鍵點就剩下一個了,那就是空間。

身高173cm的體驗者在前排座椅調到最低的情況下能有一拳的頭部空間,比較寬裕;同樣的體驗者把第二排的位置調到最前面的話,有一拳二指的頭部和一拳三指的腿部空間,其實只要第二排的老闆稍微調后一點就幾乎是頭等艙的享受了;此時去到第三排的話,同一位體驗者則有一拳的頭部空間和兩拳多的腿部空間。

大家都可以看到新GL8的空間表現是無可挑剔的,同時發現第三排座椅的坐墊高度也很適合成年人乘坐,即使是長途路上乘坐在第三排也不會感到憋屈。

試駕體驗:動力匹配是驚喜

新一代GL8正式進入了渦輪行列,而且是改革得很徹底,這一代的GL8都採用了2.0T發動機+6AT手自一體變速箱的動力系統。最大馬力260ps,最大扭矩350N·m,動力參數已經完勝舊款的GL8。

實際的駕駛過程中,2.0T的動力絲毫沒有讓擔心過,加速的時候雖然不會有很強烈的推背感,但在需要超車的時候還是能給到駕駛者很充足的信心,感到欣慰的是新GL8並沒有出現明顯的渦輪遲滯的問題,即使是中低速的行駛也十分流暢。

動力匹配則是新GL8的亮點,變速箱的設定偏向於平順低油耗的表現,一般轉速差不多到3000rpm就會升檔,但是當踩下地板油之後,它又很樂意的去降擋來榨取動力。所以新GL8的動力表現並不像一個過度活躍的孩子,而更像一個穩重而有衝勁的青壯年。

懸挂方面,新GL8從扭力梁后懸升級到了四連桿獨立后懸,調校比舊款GL8稍硬了一點。但整體的舒適性卻不降反升,新GL8在高速過彎的時候車身姿態更加穩定,同時在處理顛簸的動作很乾脆,一些小的顛簸基本就是“突突”的兩下就過去了,沒有多於的跳動。所以認為新GL8的懸挂質感是相對舊款有所提升的。

總結

新一代GL8在推出之後就得到了大家的好評,無論是外觀、配置還是動力,GL8的表現都十分出色。同時在售價方面並沒有因為產品的升級而上漲到大家無法接受的水平,這也讓不少的GL8老粉絲感到安慰。中國人買車追求實用性,同時又把車當作是身份的一個象徵,認為新一代GL8在這兩個方面都是同級別里的頂級表現,難怪國內不少的老闆都樂於選擇GL8作為自己的座駕。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※超省錢租車方案

※別再煩惱如何寫文案,掌握八大原則!

※回頭車貨運收費標準

※教你寫出一流的銷售文案?

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

網頁設計最專業,超強功能平台可客製化

STM32學習筆記——printf

printf複習

當我們寫printf("%d\n", 1);的時候,printf函數並不能通過C語言語法得知第二個參數是int類型。printf是一個變參函數(variadic function):

int printf(const char *restrict format, ...);

參數的類型都是通過格式串format推導出的。如果參數類型與格式串中指定的不匹配,或提供的參數數量少於需要的,將導致未定義行為。

由於參數類型是動態的,printfscanf比靜態類型的std::coutstd::cin慢,前提是後者的眾多overhead被手動消除。

C為可變參數提供了va_startva_argva_copyva_endva_list等工具,定義在頭文件<stdarg.h>中。va_arg用於取出參數,va_copy用於拷貝參數供多次使用。引用cppreference上的例子:

#include <stdio.h>
#include <stdarg.h>
#include <math.h>
 
double sample_stddev(int count, ...) 
{
    /* Compute the mean with args1. */
    double sum = 0;
    va_list args1;
    va_start(args1, count);
    va_list args2;
    va_copy(args2, args1);   /* copy va_list object */
    for (int i = 0; i < count; ++i) {
        double num = va_arg(args1, double);
        sum += num;
    }
    va_end(args1);
    double mean = sum / count;
 
    /* Compute standard deviation with args2 and mean. */
    double sum_sq_diff = 0;
    for (int i = 0; i < count; ++i) {
        double num = va_arg(args2, double);
        sum_sq_diff += (num-mean) * (num-mean);
    }
    va_end(args2);
    return sqrt(sum_sq_diff / count);
}
 
int main(void) 
{
    printf("%f\n", sample_stddev(4, 25.0, 27.3, 26.9, 25.7));
}

<stdio.h>還定義了vprintf系列函數,與不帶v的相比,可變參數...都換成了va_list的實例:

int vprintf(const char *format, va_list vlist);

可以藉此實現自己的printf

可變參數在傳遞的過程中會被執行默認參數提升(default argument promotion),對於整數類型執行整數提升(提升為intunsigned int),對於float類型提升成double

格式串format中的普通字符直接拷貝到輸出流,由%引導的稱為轉換格式(conversion specification),在%和轉換說明符(conversion specifier)之間可以有若干修飾符,實現對齊、精度等功能,轉換說明符有csdf等,詳見cppreference。

UART實現

單片機開發板並沒有可以用於輸出的控制台,printf調用最後都會歸結為_write函數:

int _write(int file, char* ptr, int len);

_write函數需要把ptr指向的len字節的數據以想要的形式發送,在此就沿用上一篇中的UART異步IO,於是printf就可以打印在串口上了。

為了方便日後使用,我把USART相關的代碼抽離出來放在一個新的源文件里,IDE生成的代碼去掉MX_USART1_UART_InitUSART1_IRQHandler兩個函數,再加上這一對文件就可以使用了。

usart1.h

#include <stdio.h>

void MX_USART1_UART_Init();
void usart1_transmit(char c);
char usart1_receive();

usart1.c

#include "usart1.h"

#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include "cmsis_gcc.h"
#include "stm32f4xx_hal.h"

typedef char queue_element_t;

typedef struct
{
  uint16_t mask;
  uint16_t head;
  uint16_t tail;
  queue_element_t data[0];
} queue_t;

static inline queue_t* queue_create(uint16_t _size)
{
  if (_size & (_size - 1))
    _size = 256;
  queue_t* q = malloc(sizeof(queue_t) + _size * sizeof(queue_element_t));
  if (q)
  {
    q->mask = _size - 1;
    q->head = q->tail = 0;
  }
  return q;
}

static inline bool queue_empty(const queue_t* _queue)
{
  return _queue->head == _queue->tail;
}

static inline uint16_t queue_size(const queue_t* _queue)
{
  return (_queue->tail - _queue->head) & _queue->mask;
}

static inline uint16_t queue_capacity(const queue_t* _queue)
{
  return _queue->mask;
}

static inline queue_element_t queue_peek(const queue_t* _queue)
{
  return _queue->data[_queue->head];
}

static inline void queue_push(queue_t* _queue, const queue_element_t _ele)
{
  _queue->data[_queue->tail] = _ele;
  _queue->tail = (_queue->tail + 1) & _queue->mask;
}

static inline void queue_pop(queue_t* _queue)
{
  _queue->head = (_queue->head + 1) & _queue->mask;
}

extern UART_HandleTypeDef huart1;
extern void Error_Handler();
queue_t* tx_buffer;
queue_t* rx_buffer;

void USART1_IRQHandler()
{
  uint32_t isrflags   = USART1->SR;
  uint32_t cr1its     = USART1->CR1;
  uint32_t errorflags = 0x00U;
  errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
  if (errorflags == RESET)
  {
    if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
    {
      queue_push(rx_buffer, USART1->DR);
      return;
    }
    if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
    {
      USART1->DR = queue_peek(tx_buffer);
      queue_pop(tx_buffer);
      if (queue_empty(tx_buffer))
        USART1->CR1 &= ~USART_CR1_TXEIE & UART_IT_MASK;
      return;
    }
  }
  HAL_UART_IRQHandler(&huart1);
}

void MX_USART1_UART_Init()
{
  tx_buffer = queue_create(1024);
  rx_buffer = queue_create(1024);
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  USART1->CR1 |= USART_CR1_RXNEIE & UART_IT_MASK;
}

void usart1_transmit(char c)
{
  uint16_t capacity = queue_capacity(tx_buffer);
  bool ok = false;
  while (1)
  {
    __disable_irq();
    ok = capacity - queue_size(tx_buffer) >= 1;
    if (ok)
      break;
    __enable_irq();
    __NOP();
  }
  queue_push(tx_buffer, c);
  USART1->CR1 |= USART_CR1_TXEIE & UART_IT_MASK;
  __enable_irq();
}

char usart1_receive()
{
  bool ok = false;
  while (1)
  {
    __disable_irq();
    ok = !queue_empty(rx_buffer);
    if (ok)
      break;
    __enable_irq();
    __NOP();
  }
  char c = queue_peek(rx_buffer);
  queue_pop(rx_buffer);
  __enable_irq();
  return c;
}

int _write(int file, char* ptr, int len)
{
  for (int i = 0; i != len; ++i)
    usart1_transmit(*ptr++);
  return len;
}

main.c(部分):

#include "main.h"
#include "usart1.h"

UART_HandleTypeDef huart1;
uint8_t count = 0;

void SystemClock_Config(void);
static void MX_GPIO_Init(void);

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  while (1)
  {
    printf("Hello world: %d\n", count);
    HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
    ++count;
    HAL_Delay(500);
  }
}

ITM實現

明明已經用調試器連接了開發板和電腦,還要加個USB轉串口工具就顯得很累贅;IDE和串口監視器兩個窗口的頻繁切換也讓Alt和Tab鍵損壞的幾率增加了幾成。有沒有辦法讓開發板通過調試器和IDE就能輸出呢?

可以用ARM的ITM(Instrumentation Trace Macroblock),通過TRACESWO發送。SWO與JTAG的JTDIO是同一個引腳,用標準ST-LINK的20-pin排線可以連接,但是10-pin的簡版ST-LINK沒有引出SWO,因此要使用ITM調試不能用簡版的4線接法。

ITM無需初始化,直接調用ITM_SendChar函數即可發送,該函數定義在\Drivers\CMSIS\Include\core_cmx.h中。ITM版的_write函數,不過是把usart1_transmit換成ITM_SendChar而已。

#include "main.h"
#include <stdio.h>

void SystemClock_Config(void);
static void MX_GPIO_Init(void);

int _write(int file, char* ptr, int len)
{
  for (int i = 0; i != len; ++i)
    ITM_SendChar(*ptr++);
  return len;
}

uint8_t count = 0;

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  while (1)
  {
    printf("Hello world: %d\n", count);
    HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
    ++count;
    HAL_Delay(500);
  }
}

為了在IDE中看到printf輸出的內容,需要做幾步配置。首先進入Debug模式,在調試選項的Debugger頁啟用SWV:

找到SWV ITM Data Console窗口:

窗口右上角Configure trace,勾選Port 0:

點擊Start Trace。這樣就可以看見printf的輸出了:

雜記

好久沒更博客了。這兩周一直在做搖搖棒,硬件軟件交替着改,總算是做出一個比較穩定的显示效果了。計劃本月再更兩篇。

有一次下載器與搖搖棒的連接有鬆動,數據傳輸錯誤,導致熔絲位被修改,時鐘源選擇了不存在的,程序無法啟動,也無法下載新的程序。還好我帶着這塊STM32開發板,在一個引腳上產生一個較高頻率的方波,連接到單片機的晶振引腳,改回熔絲位,算是把單片機救活了。本來STM32開發板帶着是要寫這篇printf的,博客沒寫,倒是有救場的用途。

printf相對的scanf,我也嘗試過實現,但是有兩個問題,一是我沒有找到在STM32CubeIDE中如何通過ITM向單片機發送,二是_read函數的len參數總是1024,這是想讓我一次性讀1024個字節再返回嗎?

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

※別再煩惱如何寫文案,掌握八大原則!

小師妹學JavaIO之:文件File和路徑Path

簡介

文件和路徑有什麼關係?文件和路徑又隱藏了什麼秘密?在文件系統的管理下,創建路徑的方式又有哪些?今天F師兄帶小師妹再給大家來一場精彩的表演。

文件和路徑

小師妹:F師兄我有一個問題,java中的文件File是一個類可以理解,因為文件裡面包含了很多其他的信息,但是路徑Path為什麼也要單獨一個類出來?只用一個String表示不是更簡單?

更多精彩內容且看:

  • 區塊鏈從入門到放棄系列教程-涵蓋密碼學,超級賬本,以太坊,Libra,比特幣等持續更新
  • Spring Boot 2.X系列教程:七天從無到有掌握Spring Boot-持續更新
  • Spring 5.X系列教程:滿足你對Spring5的一切想象-持續更新
  • java程序員從小工到專家成神之路(2020版)-持續更新中,附詳細文章教程

更多內容請訪問www.flydean.com

萬物皆有因,沒有無緣無故的愛,也沒有無緣無故的恨。一切真的是妙不可言啊。

我們來看下File和path的定義:

public class File
   implements Serializable, Comparable<File>
public interface Path
    extends Comparable<Path>, Iterable<Path>, Watchable

首先,File是一個類,它表示的是所有的文件系統都擁有的屬性和功能,不管你是windows還是linux,他們中的File對象都應該是一樣的。

File中包含了Path,小師妹你且看,Path是一個interface,為什麼是一個interface呢?因為Path根據不同的情況可以分為JrtPath,UnixPath和ZipPath。三個Path所對應的FileSystem我們在上一篇文章中已經討論過了。所以Path的實現是不同的,但是包含Path的File是相同的。

小師妹:F師兄,這個怎麼這麼拗口,給我來一個直白通俗的解釋吧。

既然這樣,且聽我解釋:愛國版的,或許我們屬於不同的民族,但是我們都是中國人。通俗版的,大家都是文化人兒,為啥就你這麼拽。文化版的,同九年,汝何秀?

再看兩者的實現接口,File實現了Serializable表示可以被序列化,實現了Comparable,表示可以被排序。

Path繼承Comparable,表示可以被排序。繼承Iterable表示可以被遍歷,可以被遍歷是因為Path可以表示目錄。繼承Watchable,表示可以被註冊到WatchService中,進行監控。

文件中的不同路徑

小師妹:F師兄,File中有好幾個關於Path的get方法,能講一下他們的不同之處嗎?

直接上代碼:

public void getFilePath() throws IOException {
        File file= new File("../../www.flydean.com.txt");
        log.info("name is : {}",file.getName());

        log.info("path is : {}",file.getPath());
        log.info("absolutePath is : {}",file.getAbsolutePath());
        log.info("canonicalPath is : {}",file.getCanonicalPath());
    }

File中有三個跟Path有關的方法,分別是getPath,getAbsolutePath和getCanonicalPath。

getPath返回的結果就是new File的時候傳入的路徑,輸入什麼返回什麼。

getAbsolutePath返回的是絕對路徑,就是在getPath前面加上了當前的路徑。

getCanonicalPath返回的是精簡后的AbsolutePath,就是去掉了.或者..之類的指代符號。

看下輸出結果:

 INFO com.flydean.FilePathUsage - name is : www.flydean.com.txt
 INFO com.flydean.FilePathUsage - path is : ../../www.flydean.com.txt
 INFO com.flydean.FilePathUsage - absolutePath is : /Users/flydean/learn-java-io-nio/file-path/../../www.flydean.com.txt
 INFO com.flydean.FilePathUsage - canonicalPath is : /Users/flydean/www.flydean.com.txt

構建不同的Path

小師妹:F師兄,我記得路徑有相對路徑,絕對路徑等,是不是也有相應的創建Path的方法呢?

當然有的,先看下絕對路徑的創建:

public void getAbsolutePath(){
        Path absolutePath = Paths.get("/data/flydean/learn-java-io-nio/file-path", "src/resource","www.flydean.com.txt");
        log.info("absolutePath {}",absolutePath );
    }

我們可以使用Paths.get方法傳入絕對路徑的地址來構建絕對路徑。

同樣使用Paths.get方法,傳入非絕對路徑可以構建相對路徑。

public void getRelativePath(){
        Path RelativePath = Paths.get("src", "resource","www.flydean.com.txt");
        log.info("absolutePath {}",RelativePath.toAbsolutePath() );
    }

我們還可以從URI中構建Path:

public void getPathfromURI(){
        URI uri = URI.create("file:///data/flydean/learn-java-io-nio/file-path/src/resource/www.flydean.com.txt");
        log.info("schema {}",uri.getScheme());
        log.info("default provider absolutePath {}",FileSystems.getDefault().provider().getPath(uri).toAbsolutePath().toString());
    }

也可以從FileSystem構建Path:

public void getPathWithFileSystem(){
            Path path1 = FileSystems.getDefault().getPath(System.getProperty("user.home"), "flydean", "flydean.txt");
           log.info(path1.toAbsolutePath().toString());

            Path path2 = FileSystems.getDefault().getPath("/Users", "flydean", "flydean.txt");
            log.info(path2.toAbsolutePath().toString());

        }

總結

好多好多Path的創建方法,總有一款適合你。快來挑選吧。

本文的例子https://github.com/ddean2009/learn-java-io-nio

本文作者:flydean程序那些事

本文鏈接:http://www.flydean.com/java-io-file-path/

本文來源:flydean的博客

歡迎關注我的公眾號:程序那些事,更多精彩等着您!

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※推薦評價好的iphone維修中心

網頁設計最專業,超強功能平台可客製化

※別再煩惱如何寫文案,掌握八大原則!

【Flutter實戰】移動技術發展史

老孟導讀:大家好,這是【Flutter實戰】系列文章的第一篇,這並不是一篇Flutter技術文章,而是介紹智能手機操作系統、跨平台技術的演進以及我對各種跨平台技術看法的文章。

智能手機操作系統

塞班(Symbian)系統

後浪們可能都沒有聽說過塞班系統,而很多前浪們也會詫異,塞班是智能手機操作系統嗎?讓我們先來看下智能手機的定義:

智能手機,是指像個人電腦一樣,具有獨立的操作系統,獨立的運行空間,可以由用戶自行安裝軟件、遊戲、導航等第三方服務商提供的程序,並可以通過移動通訊網絡來實現無線網絡接入的手機類型的總稱。目前智能手機的發展趨勢是充分加入了人工智能、5G等多項專利技術,使智能手機成為了用途最為廣泛的專利產品。

所以按照如上的定義,塞班系統屬於智能手機操作系統,那為什麼很多人都認為塞班系統不屬於智能手機操作系統呢?主要是因為塞班和現在的Android、iOS智能系統比起來差遠了。

雖然現在塞班系統已經Game Over了,但當年塞班系統是當之無愧的王者,根本就沒有一個與之匹配的對手。

2008年12月2日,塞班公司被諾基亞收購。

2011年12月21日,諾基亞官方宣布放棄塞班品牌。由於缺乏新技術支持,塞班的市場份額日益萎縮。

截止至2012年2月,塞班系統的全球市場佔有量僅為3%。

2012年5月27日,諾基亞徹底放棄開發塞班系統,但是服務將一直持續到2016年。

2013年1月24日晚間,諾基亞宣布,今後將不再發布塞班系統的手機,意味着塞班這個智能手機操作系統,在長達14年的歷史之後,終於迎來了謝幕。

至此,塞班時代終結,一個時代的終結,必將伴隨着新時代的到來。

Windows Phone

Windows Phone(簡稱為WP)是微軟於2010年10月21日正式發布的一款手機操作系統,初始版本命名為Windows Phone7.0。

  • 2011年9月27日,微軟發布升級版Windows Phone 7.5,這是首個支持簡體中文的系統版本。
  • 2012年6月21日,微軟正式發布Windows Phone 8,全新的Windows Phone 8捨棄了老舊Windows CE內核,採用了與Windows系統相同的Windows NT內核,支持很多新的特性。由於內核的改變,所有Windows Phone 7.5系統的手機都將無法升級至Windows Phone 8。
  • 2015年1月22日,微軟將Windows Phone 10更名為Windows 10 for Phone。
  • 2015年5月14日,微軟官網正式將智能手機上的版本命名為“Windows 10 Mobile” 。
  • 2019年12月10日,微軟停止對Windows 10 Mobile的支持。

2019年12月10日這一天,微軟宣布停止對Windows 10 Mobile的支持,也就宣告Windows 10 Mobile告別了歷史的舞台。

Windows Phone當年的市場份額一度超過50%,到退出歷史的舞台,在我看來微軟犯了一個很大的錯誤:

那就是Windows Phone 8的發布,由於使用了新的內核導致以前的手機無法升級而且軟件不向下兼容,導致用戶和開發者極度不爽,用戶剛買了手機,結果你告訴用戶系統不能升級?

新系統導致以前開發的App無法運行,開發者重新開發一遍?而且還要維護兩套?

系統最核心的資產是生態,當你拋棄了開發者也就意味着生態的殘缺,沒有大量優質的應用用戶怎麼可能買你的手機?

Android

Android系統大家都非常熟悉了,畢竟是當前市場份額最大的移動操作系統,看一下Android的發展歷程:

  • 2003年10月,Andy Rubin等人創建Android公司,並組建Android團隊。
  • 2005年8月17日,Google低調收購了成立僅22個月的高科技企業Android及其團隊。安迪魯賓成為Google公司工程部副總裁,繼續負責Android項目。
  • 2008年,在GoogleI/O大會上,谷歌提出了AndroidHAL架構圖,在同年8月18號,Android獲得了美國聯邦通信委員會(FCC)的批准,在2008年9月,谷歌正式發布了Android 1.0系統,這也是Android系統最早的版本。
  • 2009年4月,谷歌正式推出了Android 1.5這款手機,從Android 1.5版本開始,谷歌開始將Android的版本以甜品的名字命名,Android 1.5命名為Cupcake。
  • 2010年10月,谷歌宣布Android系統達到了第一個裡程碑,即电子市場上獲得官方数字認證的Android應用數量已經達到了10萬個,Android系統的應用增長非常迅速。
  • 2011年8月2日,Android手機已佔據全球智能機市場48%的份額,並在亞太地區市場佔據統治地位,終結了塞班系統的霸主地位,躍居全球第一。
  • 今年(2020年)即將發布Android 11。

iOS

iOS是由蘋果公司開發的移動操作系統 。蘋果公司最早於2007年1月9日的Macworld大會上公布這個系統,其發展歷程如下:

  • 2007年10月17日,蘋果公司發布了第一個本地化iPhone應用程序開發包(SDK),並且計劃在2月發送到每個開發者以及開發商手中。
  • 2010年6月,蘋果公司將“iPhone OS”改名為“iOS”,同時還獲得了思科iOS的名稱授權。
  • 2010年第四季度,蘋果公司的iOS佔據了全球智能手機操作系統26%的市場份額。
  • 2013年6月10日,蘋果公司在WWDC 2013上發布了iOS 7,幾乎重繪了所有的系統App,去掉了所有的仿實物化,整體設計風格轉為扁平化設計。將於2013年秋正式開放下載更新。
  • 2016年9月14日,蘋果發布iOS 10正式版,這是蘋果推出移動操作系統以來最大的一次更新,尤其增加了很多特別適應中國國情的功能,比如騷擾電話識別、蘋果地圖進一步本地化等。
  • 2018年9月13日,2018蘋果秋季新品發布會上,蘋果CEO庫克介紹了蘋果生態的一些數據。他表示,搭載蘋果iOS系統設備已達20億部。
  • 2020年5月21日,蘋果發布iOS 13.5正式版,iOS 13.5加快了配備面容ID的設備在用戶佩戴口罩時显示密碼欄的速度,並加入了“暴露通知”API以支持來自公共衛生管理機構的COVID-19接觸追蹤App。

跨平台開發演進

2008年7月IPhone推出第一代手機IPhone 3G,同年9月谷歌正式發布了Android 1.0系統,標志著我們正式步入移動端發展期,按照技術開發的歷程移動端(目前特指Android和iOS)的發展大致可以分為4個階段:原生階段->Hybird階段->RN階段->Flutter 階段。

原生階段

使用原生語言(Android使用Java或Kotlin,iOS使用Objective-C 或 Swift )開發應用,稱之為原生階段

在此階段發現一樣的功能需要在Android和iOS兩端開發,開發和維護成本較高,同時無動態化更新能力,緊急問題的修復和添加新功能都需要到相應平台發版,尤其是iOS審核的周期非常長,在國內Android雖然有動態化方案,但如果上架Google Play很有可能審核不通過或者下架,iOS也有動態化,但蘋果官方基本審核不通過,所以原生的動態化更新受政策影響很大。

從開發者的角度出發,是否有一種方案可以開發一套代碼在多個平台運行且可以動態化更新,無需在走平台的審核。基於這個需求H5興起,也就是我們所說的Hybird階段。

Hybird階段

Hybird實現的基本原理是通過原生的WebView容器加載H5網頁進行渲染,通過JavaScript Bridge調用一部分系統能力,同步更新服務器上的H5網頁也實現了動態更新,俗稱混合應用。

當時大量的公司使用此方案進行開發,最出名的就是Facebook,早期的Facebook在H5上投入了大量的精力,一次開發、快速迭代這是使用H5技術巨大的優勢。

然而一切看似美好,但很快發現,H5方案存在致命的缺陷-用戶體驗極差

Facebook創始人兼CEO馬克·扎克伯格在接受採訪的時候承認:專註在HTML 5上面是他有史以來犯過的最大的錯誤。

然而福兮禍所伏,雖然在Facebook上大量使用H5而導致用戶體驗極差,但Facebook基於強大的H5技術積累開發出了偉大的React框架,此框架是React Native框架的基礎。

React Native階段

React Native簡稱RN,是FaceBook在2015年開源,基於 JavaScript,具備動態配置能力跨平台開發框架。React Native框架原理如下:

React Native 使用React開發,然後生成虛擬DOM樹,虛擬 DOM 是一個 JavaScript 的樹形結構,通過虛擬DOM樹映射到不同平台的本地控件,最終显示的UI是原生控件,因此在性能體驗上和原生非常相近。和React Native 類似的框架還有阿里巴巴的Weex框架,Weex是在React Native基礎上重新設計了一套開發模式,原理上和React Native 一樣。

React Native 解決了繼承了H5的優點,同時解決了性能體驗上的問題,2015年React Native一經發布,就在技術圈引起了巨大的反響,在當時看來React Native 是一個非常完美的跨平台解決方案,很快大量開發者湧入。

當年使用React Native 的開發者最擔心的不是React Native 性能如何?體驗如何?而是擔心蘋果會不會封掉React Native,可想而之React Native 的火爆程度,當年著名的JSPatch事件起初,起初大家都在說蘋果開始對React Native下手了,雖然後來證實和React Native無關,但多多少少都對React Native 開發者造成了一定的影響。

隨着時間的流逝,發現React Native 和原生橋接的成本非常高,在複雜場景下會出現嚴重的性能問題,比如早期的ListView滑動卡頓問題。

React Native要橋接到原生控件,但Android和IOS控件的差異導致React Native無法統一API,有的屬性IOS支持,Android不支持,有的Android支持,IOS不支持,這就導致經常需要開發Android和IOS兩套插件,隨着項目的複雜度提升,也導致維護成本大幅提升。

還有一個很大的問題就是React Native 依賴於 Facebook 的維護,而每次iOS和Android系統版本更新,很大程度上會受到影響。

小程序

從技術上來說,小程序(指微信小程序,下同)並不是新的跨平台方案,它使用瀏覽器內核來渲染界面,小部分由原生組件渲染,原理圖如下:

小程序的運行環境分成渲染層和邏輯層,通信會經由微信客戶端(Native)做中轉。

微信小程序目前來看是非常成功的,在我看來微信小程序成功主要原因並不是因為技術,而是生態,當然微信小程序體驗也是非常好的。

對商家來說,微信小程序擁有月活10億的微信用戶,獲客成本低,這是一個流量極佳的平台,因此很多商家開發了體驗極好的小程序,甚至一些商家把主要平台遷移到了微信小程序。

對於用戶來說,無需下載,用完就走,極大的提升了用戶體驗,微信提供基礎服務平台,商家獲客成本低,用戶體驗提升,三方形成完美的平衡,因此微信小程序的生態越來越完善。

除了小程序外,類似的方案還有百度的輕應用和快應用,但都不溫不火。

Flutter 階段

千呼萬喚始出來,主角-Flutter終於登場了,Flutter是谷歌的移動UI框架,可以快速在iOS和Android上構建高質量的原生用戶界面。

Flutter吸收了前面的經驗,它既沒有使用WebView,也沒有使用原生控件進行繪製,而是自己實現了一套高性能渲染引擎來繪製UI,這個引擎就是大名鼎鼎的Skia,Skia是一個2D繪圖引擎庫,Chrome和Android都是採用Skia作為引擎。Flutter完美的解決了跨平台代碼復用和性能問題,大家都在感嘆:似乎UI迎來了終極解決方案。

Flutter局限性

Flutter並不是無所不能的,當你選取Flutter作為技術方案時,首先要了解Flutter無法實現哪些功能。

UI平台一致性

由於Flutter使用自己的引擎進行UI渲染,而不是用原生控件渲染,導致控件显示效果和原生不是完全一樣,雖然肉眼看起來基本一樣,但還是有一些細微的差別,尤其當Android和iOS系統升級導致原生控件效果發生變化時,Flutter開發的App並不會進行相應的變化,如果您的App需要原生控件保持完全一致,Flutter可能並不適合您。

動態化更新

動態化功能在國內來說是一項非常重要的功能,Google官方已經明確現階段不會實現動態化功能。

此功能並不是技術上無法實現,更多的還是政策和法律上的約束。

因此如果您的App需要動態化功能,那麼Flutter可能並不適合您。

總結

既然Flutter已經如此優秀了,那是不是以後使用Flutter就可以了呢?答案是否定的,未來很長一段時間應該是原生、Hybird、React Native、Flutter共存時代。

  • 原生開發是無法完全避開的,一些硬件(比如藍牙、傳感器等)功能、音視頻和ARVR等相關功能必須使用原生開發,有人說我開發藍牙功能沒用寫原生代碼啊,直接引入即可,你沒有寫,那是因為有人為你封裝好了第三方插件。
  • Hybird雖然有一些缺陷,但依然有其使用的場景,比如京東、天貓App中的營銷活動都是是H5實現的。
  • React Native可以使用原生控件渲染,因此,如果您需要使用原生控件而又想跨平台,React Native是不錯的選擇。

交流

老孟Flutter博客地址(330個控件用法):http://laomengit.com

歡迎加入Flutter交流群(微信:laomengit)、關注公眾號【老孟Flutter】:

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

網頁設計最專業,超強功能平台可客製化

※別再煩惱如何寫文案,掌握八大原則!

Elasticsearch 別管原理,先run起來

少點代碼,多點頭髮

本文已經收錄至我的GitHub,歡迎大家踴躍star 和 issues。

https://github.com/midou-tech/articles

看文章有兩點需要注意:

  • 本公號講解的Elasticsearch是基於7.7.0版本,你們在閱讀一些相關書籍和博客注意版本,不同版本很多概念會有出入。

  • 文章寫作過程中會經常將Elasticsearch簡寫為Es,閱讀過程中需要注意。

一般學習一個新的技術或者產品,第一步就是用起來。什麼設計理論,框架源碼,都別和我談,先run起來。這也是在公司看別人項目的絕招。

用起來,有一個很明顯的點,是你能感受到他,不然天天看理論知識,看源碼會讓你覺得你好像懂了,但又心裏沒底,最終會導致你走火入魔。

今天龍叔的主題就是 學Es,先run起來,用起來之後在去探索內部更多問題和原理。

Elasticsearch

Elasticsearch安裝

Elasticsearch 的底層是開源庫 Lucene。但是,你沒法直接用 Lucene,必須自己寫代碼去調用它的接口。Elasticsearch 是 Lucene 的封裝,提供了 REST API 的操作接口,開箱即用。

Elasticsearch 需要 Java 8 環境。如果你的機器還沒安裝 Java,可以在網上找個教程安裝,注意要保證環境變量JAVA_HOME正確設置。

安裝完 Java,就可以跟着 官方文檔:https://www.elastic.co/guide/en/elasticsearch/reference/current/zip-targz.html 安裝 Elasticsearch。我這裏就直接下載壓縮包比較簡單。

#mac和linux上安裝教程一樣的
# 下載
$ wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.7.0-darwin-x86_64.tar.gz
$ wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.7.0-darwin-x86_64.tar.gz.sha512
$ shasum -a 512 -c elasticsearch-7.7.0-darwin-x86_64.tar.gz.sha512 
#解壓
$ tar -xzf elasticsearch-7.7.0-darwin-x86_64.tar.gz
$ cd elasticsearch-7.7.0/

接着,進入解壓后的目錄,運行下面的命令,啟動 Elasticsearch。

$ ./bin/elasticsearch

如果一切正常,那可能是run起來了,Es默認打開9200端口。測試下是否啟動成功,用 curl 工具測試(這個工具後面會寫一篇文章介紹,還有上面用的wget),也可以在瀏覽器訪問。

$ curl localhost:9200 #測試命令
{
  "name" : "MacBook-Pro.local",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "Z1NxCjE4T6CgTjZmpAVe_A",
  "version" : {
    "number" : "7.7.0",
    "build_flavor" : "default",
    "build_type" : "tar",
    "build_hash" : "81a1e9eda8e6183f5237786246f6dced26a10eaf",
    "build_date" : "2020-05-12T02:01:37.602180Z",
    "build_snapshot" : false,
    "lucene_version" : "8.5.1",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

請求9200端口,Elastic 返回一個 JSON 對象,包含當前節點、集群、版本等信息。

收到這樣一個JSON對象,說明啟動成功。

安裝整體沒什麼壓力,java環境裝好,基本就是開箱即用。程序員最喜歡使用這樣的中間件,開箱即用,從不管箱子裏面是啥。

基本概念

本來run起來就準備說搞點數據進去,在和Es進行交互起來,但是正在準備寫數據進索引的時候,發現不對勁。

可能有人根本不知道什麼是索引?什麼Document。於是 就來了,先普及下基本概念。

節點(Node) 與集群( Cluster)

Elastic 本質上是一個分佈式數據庫,允許多台服務器協同工作,每台服務器可以運行多個 Elastic 實例。

單個 Elastic 實例稱為一個節點(node)。一組節點構成一個集群(cluster)。

索引(Index)

Elastic 會索引所有字段,經過處理后寫入一個反向索引(Inverted Index),也經常稱之為倒排索引。查找數據的時候,直接查找該索引。

Elastic 數據管理的頂層單位就叫做 Index(索引)。它是單個數據庫的同義詞。每個 Index (即數據庫)的名字必須是小寫。

文檔(Document)

Index 裏面單條的記錄稱為 Document(文檔)。許多條 Document 構成了一個 Index。

寫點數據進Es

基本概念已經有了,知道查找是通過倒排索引進行的,所以數據肯定是存放在索引裏面的。

我們現在要寫數據進Es,其實就是把數據寫到Es的索引(index)中,前面已經把Es啟動起來了,並沒有創建索引。

今天寫數據就不寫代碼了,利用ES的一些封裝很好的接口,直接命令行操作,後期在用代碼寫數據進Es。

先創建一個index ,使用curl 工具在命令行操作,這是一個put請求。

$curl -X PUT 'localhost:9200/user'

查看索引是否以及創建成功

$ curl -X GET 'http://localhost:9200/_cat/indices?v'

這個get請求可以查看當前節點的所有索引

妥妥的已經創建成功

順便說下,刪除一個索引的命令,DELETE參數表示刪除

$curl -X DELETE 'localhost:9200/user'

到這裏索引已經創建好了,可以寫點數據進去了。使用接口 /index/_doc/id ,/索引名/_doc/doc_id

$ curl -X PUT -H 'Content-Type: application/json' 'localhost:9200/user/_doc/1' -d ' {  "name": "龍躍十二",  "title": "工程師",  "desc": "一個分享互聯網技術和心路歷程的star" }'

查看當前索引下的所有數據

$ curl 'localhost:9200/user/_search?pretty=true 

到這裏基本我們已經可以寫數據到指定索引了,生產場景不會這麼寫數據的,都是用代碼寫海量數據進ES的,這就幾條數據也沒什麼搜索性能可談的。

我之前工作中日誌數據都是TB級別的寫到Es中,當遇到這種數據量的搜索時才會感受到搜索引擎的魅力,才會意識到Es的重要性。

這裏主要是練手和跑通流程,所以造了一些數據到Es中

和ES進行交互

其實寫數據進Es已經是一種交互了,在講一些其他的交互接口

目前講的交互方式主要是通過原生的請求的方式,還沒有上升到界面操作,後期在學習的過程中會展現出來。

查詢交互

使用 GET 方法,直接請求/Index/_search,就會返回所有記錄。

$ curl 'localhost:9200/user/_search?pretty=true'
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "user",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "name" : "龍躍十二",
          "title" : "工程師",
          "desc" : "一個分享互聯網技術和心路歷程的star"
        }
      },
      {
        "_index" : "user",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : {
          "name" : "三y",
          "title" : "工程師",
          "desc" : "只有光頭才能變得更強"
        }
      },
      {
        "_index" : "user",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : {
          "name" : "敖丙",
          "title" : "工程師",
          "desc" : "一個互聯網苟且偷生的工具人"
        }
      }
    ]
  }
}

上面代碼中,返回結果的 took字段表示該操作的耗時(單位為毫秒),timed_out字段表示是否超時,hits字段表示命中的記錄,裏面子字段的含義如下。

  • total:返回記錄數,本例是2條。
  • max_scor:最高的匹配程度,本例是1.0。
  • hits:返回的記錄組成的數組。

返回的記錄中,每條記錄都有一個_score字段,表示匹配的程序,默認是按照這個字段降序排列。

Es的查詢語法還有很多,後面在結合實戰項目的時候會講解其他語法,你也可以看下官網語法介紹 官網查詢語法。

數據操作交互

新增一條doc記錄的語法示例如下,可以不用指定doc_id的,Es會默認有一個doc_id。

$ curl -X PUT -H 'Content-Type: application/json' 'localhost:9200/user/_doc/2' -d ' {  "name": "敖丙",  "title": "工程師",  "desc": "一個互聯網苟且偷生的工具人" }'

刪除一條doc記錄的語法是 /Index/_doc/doc_id

$ curl -X DELETE  'localhost:9200/user/_doc/1'

更新一條記錄的語法示例

$ curl -X PUT -H 'Content-Type: application/json' 'localhost:9200/user/_doc/2' -d ' {  "name": "三太子敖丙",  "title": "工程師",  "desc": "一個互聯網苟且偷生的工具人" }'

總結一下

本篇文章,我們把Es從官網下載下來,可以run起來,可以寫數據進去,可以查詢,學習了一些簡單的交互語法。

當然Es的魅力不在於此,Es的魅力之一在於可以對海量數據進行高效的檢索。

下篇文章出一個關於Es的寫作大綱,方便大家在看的過程中有一個整理的輪廓。

Es整個知識點我也是邊學邊寫,有什麼不對的地方,還希望大佬們儘管指出來。

龍躍十二

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

網頁設計最專業,超強功能平台可客製化

※回頭車貨運收費標準

計算機網絡之網絡層

網絡層概述

  網絡層的目的是實現兩個端系統之間的數據透明傳送,具體功能包括尋址和路由選擇、連接的建立、保持和終止等。它提供的服務使傳輸層不需要了解網絡中的數據傳輸和交換技術。如果您想用盡量少的詞來記住網絡層,那就是”路徑選擇、路由及邏輯尋址”。

  網絡層中涉及眾多的協議,其中包括最重要的協議,也是TCP/IP的核心協議——IP協議。IP協議非常簡單,僅僅提供不可靠、無連接的傳送服務。IP協議的主要功能有:無連接數據報傳輸、數據報路由選擇和差錯控制。與IP協議配套使用實現其功能的還有地址解析協議ARP、逆地址解析協議RARP、因特網報文協議ICMP、因特網組管理協議IGMP。

IP協議詳解

虛擬互連網絡

  實際的計算機網絡是錯綜複雜的,物理設備通過使用IP協議,屏蔽了物理網絡之間的差異,當網絡中的主機使用IP協議連接時,則無需關注網絡細節。IP協議使得複雜的實際網絡變為一個虛擬互連的網絡,還使得網絡層可以屏蔽底層細節而專註網絡層的數據轉發,IP協議解決了在虛擬網絡中數據報傳輸路徑的問題。

  IP地址長度為32位,常分成4個8位,IP地址常使用點分十進制來表示(0~255.0~255.0~255.0~255),也就是共有\(2^{32} = 4294961296\)個IP地址。下圖是IP協議的格式:

我們來看看IP協議的首部:

4位版本 4位首部長度 8位服務類型(TOS) 16位總長度(字節)
16位標識 3位標誌 13位片偏移
8位生存時間(TTL) 8位協議 16位首部校驗和
32位源IP地址
32位目的IP地址
選項options(若有)
IP數據

版本:佔4位,指的是IP協議的版本,通信雙方的版本必須一致,當前主流版本是4,即IPv4,也有IPv6
首部位長度:佔4位,最大數值為15,表示的是IP首部長度,單位是“32位字”(4個字節),也即是IP首部最大長度為60字節
總長度:佔16位,最大數值為65535,表示的是IP數據報總長度(IP首部+IP數據)
TTL:佔8位,表明IP數據報文在網絡中的壽命,每經過一個設備,TTL減1,當TTL=0時,網絡設備必須丟棄該報文。作用:避免數據在網絡中無限傳輸,當這個網絡報文找不到目的機器時,而進行無限傳輸,來浪費帶寬資源
協議:佔8位,表明IP數據所攜帶的具體數據是什麼協議的(如:TCP、UDP等)

協議名 ICMP IGMP IP TCP UDP OSPF
字段值 1 2 4 6 17 89

首部校驗和:佔16位,校驗IP首部是否有出錯

IP協議的轉發流程

  在數據鏈路層的學習中我們知道了MAC地址表,由於IP協議的轉發是通過逐跳(hop-by-hop)來實現的,所以在網絡層中,存在一個類似於MAC地址表的路由表,路由表是存儲的目的IP地址和下一跳IP地址的映射,計算機或者路由器都擁有路由表。路由表如下:

目的IP地址 下一跳IP地址
IP1 IP4
IP2 IP5
IP3 IP6

A設備是如何跨設備將數據發送給C設備的呢?

A設備向C設備在網絡層中傳輸數據的過程如下:

  1. A發出目的地為C的IP數據報,查詢路由表發現下一跳為E
  2. A將數據報發送給E
  3. E查詢路由表發現下一跳為F,將數據報發送給F
  4. F查詢路由表發現目的地C直接連接,將數據報發送給C

現在結合數據鏈路層和網絡層,再來看一下跨設備傳輸數據的過程:

  1. A發出目的地為C的IP數據報,查詢路由表發現下一跳為E
  2. A將IP數據報交給數據鏈路層,並告知目的MAC地址是E
  3. 數據鏈路層填充源MAC地址A目的MAC地址E
  4. 數據鏈路層通過物理層將數據發送給E
  5. E的數據鏈路層接收到數據幀,把幀數據交給網絡層
  6. E查詢路由表,發現下一跳為F
  7. E把數據報交給數據鏈路層,並告知目的MAC地址為F
  8. E的數據鏈路層封裝數據幀併發送
  9. F的數據鏈路層接收到數據幀,把幀數據交給網絡層
  10. F查詢路由表,發現下一跳為C
  11. F把數據報交給數據鏈路層,並告知目的MAC地址為C
  12. F的數據鏈路層F封裝數據幀併發送

  從IP協議的轉發流程中我們可以看到:數據幀每一跳的MAC地址都在變化,但IP數據報每一跳的IP地址始終不變。但我們會發現一個問題,在網絡層中將數據報交給數據鏈路層,並且需要告知目的MAC地址,但是在網絡層中只知道IP地址,我們是如何知道目的MAC地址的呢?這就是ARP協議做的事情了。

ARP協議

  ARP(Address Resolution Protocol)地址解析協議,將網絡層中的32位IP地址,通過ARP協議解析為數據鏈路層中的48位MAC地址。這個映射關係是存儲在ARP緩存表中的。arp -a命令:查看ARP緩存表

IP地址 MAC地址
192.168.83.254 00-50-56-e0-33-40
192.168.83.255 01-00-5e-00-00-16
224.0.0.251 01-00-5e-00-00-fc
239.1.2.3 01-00-5e-40-98-8f
255.255.255.255 01-00-5e-7f-ff-fa

  ARP緩存表是ARP協議和RARP協議運行的關鍵,ARP緩存表緩存了IP地址到硬件地址之間的映射關係,ARP緩存表中的記錄並不是永久有效的,有一定的期限。這是因為當你的網絡設備,換個網絡環境,網絡設備的IP地址就可能會發生改變,ARP緩存表中的原來的記錄就失效了。當ARP緩存表中有映射關係,就直接查詢ARP緩存表;如果沒有這個映射關係,ARP協議就會廣播,並記錄回應得地址信息。

  RARP(Reverse Address Resolution Protocol)逆地址解析協議,其作用與ARP協議相反,即把數據鏈路層中48位MAC地址,解析位網絡層中的32位IP地址。(R)ARP協議是TCP/IP協議棧裏面基礎的協議,ARP和RARP的操作對程序員是透明的,理解(R)ARP協議有助於理解網絡分層的細節。

IP地址的子網劃分

分類的IP地址

最小網絡號 最大網絡號 子網數量 最小主機號 最大主機號 主機數量
A 0(00000000) 127(01111111) \(2^7\) 0.0.0 255.255.255 \(2^{24}\)
B 128.0 191.255 \(2^{14}\) 0.0 255.255 \(2^{16}\)
C 192.0.0 223.255.255 \(2^{21}\) 0 255 \(2^{8}\)

特殊的主機號:主機號全0表示當前網絡段,不可分配為特定主機;主機號為全1表示廣播地址,向當前網絡段所有主機發消息

  • A類地址網絡段全0(00000000)表示特殊網絡
  • A類地址網絡段后7位全1(01111111:127)表示迴環地址
  • B類地址網絡段(10000000.00000000:128.0)是不可使用的
  • C類地址網絡段(192.0.0)是不可使用的

實際可使用各類IP地址如下:

最小網絡號 最大網絡號 子網數量 最小主機號 最大主機號 主機數量
A 1 127(01111111) \(2^7\)-2 0.0.1 255.255.254 \(2^{24}\)-2
B 128.1 191.255 \(2^{14}\)-1 0.1 255.254 \(2^{16}\)-2
C 192.0.1 223.255.255 \(2^{21}\)-1 1 254 \(2^{8}\)-2

  127.0.0.1,通常被稱為本地迴環地址(Loopback Address),不屬於任何一個有類別地址類。它代表設備的本地虛擬接口,所以默認被看作是永遠不會宕掉的接口。在Windows操作系統中也有相似的定義,所以通常在安裝網卡前就可以ping通這個本地迴環地址。一般都會用來檢查本地網絡協議、基本數據接口等是否正常的。

劃分子網

  隨着互連網應用的不斷擴大,原先的IPv4的弊端也逐漸暴露出來,即網絡號佔位太多,而主機號位太少,所以其能提供的主機地址也越來越稀缺,目前除了使用NAT在企業內部利用保留地址自行分配以外,通常都對一個高類別的IP地址進行再劃分,以形成多個子網,提供給不同規模的用戶群使用。這裏主要是為了在網絡分段情況下有效地利用IP地址,通過對主機號的高位部分取作為子網號,從通常的網絡位界限中擴展或壓縮子網掩碼,用來創建某類地址的更多子網。但創建更多的子網時,在每個子網上的可用主機地址數目會比原先減少。

上圖就把原來的C類地址劃分成了兩個子網。
  但子網號這麼多,有沒有辦法快速判斷某個IP的網絡號?這就是子網掩碼的作用了,子網掩碼是標誌兩個IP地址是否同屬於一個子網的,也是32位二進制地址,其每一個為1代表該位是網絡位,為0代表主機位。它和IP地址一樣也是使用點式十進制來表示的。如果兩個IP地址在子網掩碼的按位與的計算下所得結果相同,即表明它們共屬於同一子網中。

  子網掩碼由連續的1和連續的0組成,某一個子網的子網掩碼具備網絡號位數個連續的1

  在計算子網掩碼時,我們要注意IP地址中的保留地址,即” 0″地址和廣播地址,它們是指主機地址或網絡地址全為” 0″或” 1″時的IP地址,它們代表着本網絡地址和廣播地址,一般是不能被計算在內的。

無分類編址CIDR

  CIDR中沒有A、B、C類網絡號、和子網劃分的概念,CIDR將網絡前綴相同的IP地址稱為一個“CIDR地址塊”,注意網絡前綴是任意位數的。

網絡前綴 主機號

斜線記法:193.10.10.129/25 使用二進製表示:11000001.00001010.00001010.10000001
無分類地址CIDR相比原來的子網劃分更加 靈活:

CIDR前綴長度 掩碼點分十進制 地址數
/13 255.248.0.0 512K
/14 255.252.0.0 256K
/15 255.254.0.0 128K
/16 255.255.0.0 64K
/17 255.255.128.0 32K
/18 255.255.192.0 16K
/19 255.255.224.0 8K

網絡地址轉換NAT技術

  IPv4最多只有40+億個IP地址,早期IP地址的不合理規劃導致IP號浪費。在介紹NAT技術之前,首先要知道內網地址和外網地址。

  • 內網地址:內部機構使用,避免與外網地址重複。三類內網地址如下:
    • 10.0.0.0~10.255.255.255(支持千萬數量級設備)
    • 172.16.0.0~172.31.255.255(支持百萬數量級設備)
    • 192.168.0.0~192.168.255.255(支持萬數量級設備)
  • 外網地址:全球範圍使用,全球公網唯一

  網絡地址轉換技術是發生在本地路由器的,主要功能就是把內網的IP地址轉成外網的IP地址來進行外部的通信,並且在接收到數據之後,再把外網IP地址映射成內網IP地址,轉發到具體的某個設備上面去。

  內網多個設備使用同一個外網IP請求外網的服務,外部怎麼知道具體是哪個設備在請求的?網絡地址轉換NAT的英文全稱是Network Address Translation,NAT技術用於多個主機通過一個公有IP訪問互聯網的私有網絡中,外部主要是通過端口號來區分到底是內網的哪一個設備進行請求的,這其中有一個NA(P)T表表:示例如下:

方向 舊的地址和端口號 新的地址與端口號
192.168.2.11:6666 173.21.59.10:16666
192.168.2.10:7777 173.21.59.10:17777
173.21.59.10:16666 192.168.2.11:6666
173.21.59.10:17777 192.168.2.10:7777

NAT減緩了IP地址的消耗,但是增加了網絡通信的複雜度

ICMP協議

  ICMP協議全稱是網際控制報文協議(Internet Control Message Protocol),ICMP協議可以報告錯誤信息或者異常情況

ICMP協議首部:

8位類型 8位代碼 16位校驗和
ICMP報文數據

ICMP報文分為:差錯報告報文和詢問報文:

ICMP報文種類 類型的值 報文類型 具體代碼
差錯報告報文 3(終點不可達) 網絡不可達 0
主機不可達 1
5(重定向) 對網絡重定向 0
對主機重定向 1
11 傳輸超時
12 壞的IP頭 0
缺少其他必要參數 1
詢問報文 0或8 回送(Echo)請求或應答
13或14 時間戳(Timestamp)請求或應答

ICMP協議的應用

ping應用:我們可以通過ping命令進行簡單的網絡故障排查:

  1. ping本地迴環地址,一般情況下,都會得到返回的,如果得不到返回,則說明你的計算機的協議棧出現了問題,這個時候就可能需要重裝系統,或者是重新安裝這個協議棧
  2. ping網關地址,即路由器地址,如果能得到返回的話,則說明本機到路由器的通路是通的,如果沒有返回的話,則說明你的wifi,或者你的網線連接是有問題的
  3. ping遠端地址,如果不通的話,則說明你的家到ISP之間的網絡是故障的,此時就需要聯繫網絡服務商(移動、電信、聯通)進行排查。

Traceroute應用:Traceroute可以探測IP數據報在網絡中走過的路徑

路由概述

  思考:路由表中的下一跳地址是怎麼來的?下一跳地址是唯一的嗎?下一跳地址是最佳的嗎?路由器怎麼多,他們是怎麼協同工作的?為了解決這些問題,路由表需要一個好的算法去解決這些事情。路由算法實際上是圖論的算法,由於網絡環境複雜,使得路由算法要比圖論的算法更複雜。

  由於互聯網的規模是非常大的,互聯網環境是非常複雜的,所以我們需要對互聯網進行劃分。自治系統(Autonomous System)是指處於一個管理機構下的網絡設備群,AS內部網絡自行管理,AS對外提供一個或者多個出(入)口。自治系統內部路由的協議稱為:內部網關協議(RIP、OSPF), 自治系統外部路由的協議稱為:外部網關協議(BGP)。

路由算法

  路由算法的本質是距離矢量(DV)算法, 距離矢量(DV)算法介紹如下:

  • 每一個節點使用兩個向量\(D_i\)\(S_i\)
  • \(D_i\)描述的是當前節點到別的節點的距離
  • \(S_i\)描述的是當前節點到別的節點的下一節點
  • 每一個節點與相鄰的節點交換向量\(D_i\)\(S_i\)的信息
  • 每一個節點根據交換的信息更新自己的節點信息

現在假設有A的距離矢量信息,收到的距離矢量信息如下圖:

A通過B到各個節點得距離矢量信息如下:

A通過C到各個節點得距離矢量:並更新下一條的節點

A通過D到各個節點得距離矢量:並更新下一條的節點

A通過F到各個節點得距離矢量:並更新下一條的節點

RIP協議

  RIP(Routing Information Protocol)協議,RIP協議是使用DV算法的一種路由協議。RIP協議把網絡的跳數(hop)作為DV算法的距離,每隔30s交換一次路由信息,認為跳數>15的路由則為不可達路由。

RIP協議的過程

  1. 路由器初始化路由信息(兩個向量\(D_i\)\(S_i\))
  2. 對相鄰路由器X發過來的信息,對信息的內容進行修改(下一跳地址設置為X,所有距離加1)
    1. 檢索本地路由,將信息中新的路由插入到路由表裡面
    2. 檢索本地路由,對於下一跳為X的,更新為修改后的信息
    3. 檢索本地路由,對比相同目的的距離,如果新信息的距離更小,則更新本地路由表
  3. 如果3分鐘沒有收到相鄰的路由信息,則把相鄰路由設置為不可達(16跳)

RIP協議的優缺點:

  • 優點:實現簡單,開銷很小。
  • 缺點:故障信息傳遞慢。也就是隨便相信“隔壁老王”,“自己不思考” “視野不夠”。因為RIP協議每一個路由器它只看到相鄰路由器的信息,而看不到更遠的路由器信息,這也限制了網絡的規模。

內部網關路由協議之OSPF協議

鏈路狀態(LS)協議

  鏈路狀態(LS)協議:向所有的路由器發送消息,也就是一傳十、十傳百,只和相鄰的路由器交換信息。消息描述該路由器與相鄰路由器的鏈路狀態,每隔30s交換路由信息,只有鏈路狀態發生變化時,才發送更新信息。

Dijkstra(迪傑斯特拉)算法

  Dijkstra算法是著名的圖算法,Dijkstra算法解決有權圖從一個節點到其他節點的最短路徑問題,“以起始點為中心,向外層層擴展”。

Dijkstra(迪傑斯特拉)算法定義:

  1. 初始化兩個集合(S, U)(S為只有初始頂點點A的集合,U為其他頂點集合)
  2. 如果U不為空, 對U集合頂點進行距離的排序,並取出距離A最近的一個頂點D
    i. 將頂點D的納入S集合
    ii. 更新通過頂點D到達U集合所有點的距離(如果距離更小則更新,否則不更新)
    iii. 重複2步驟
  3. 直到U集合為空,算法完成

OSPF協議的過程

  OSPF(Open Shortest Path First:開放最短路徑優先),OSPF協議的核心是Dijkstra算法。OSPF協議的過程:路由器接入網絡,路由器向鄰居發出問候信息,與鄰居交流鏈路狀態數據庫,廣播和更新未知路由。

RIP協議 OSPF協議
從鄰居看網絡 整個網絡的拓撲
在路由器之間累加距離 Dijkstra算法計算最短路徑
頻繁、周期更新,收斂很慢 狀態變化更新,收斂很快
路由間拷貝路由信息 路由間傳遞鏈路狀態,自行計算路徑

外部網關路由協議之BGP協議

  BGP(Border Gateway Protocol: 邊際網關協議),BGP協議是運行在AS之間的一種協議。由於互聯網的規模很大,AS內部使用不同的路由協議。

  AS之間需要考慮除網絡特性以外的一些因素(政治、安全…),BGP(Border Gateway Protocol,邊界網關協議),BGP協議能夠找到一條到達目的比較好的路由,AS之間通過BGP發言人來進行路由信息的交換。BGP發言人(speaker):BGP並不關心內部網絡拓撲,AS之間通過BGP發言人交流信息,BGP Speaker可以人為配置策略。

總結:網絡層負責對子網間的數據包進行路由選擇。此外,網絡層還可以實現擁塞控制、網際互連等功能;網絡層的基本數據單位為IP數據報;包含的主要協議:IP協議(Internet Protocol,因特網互聯協議)、ICMP協議(Internet Control Message Protocol,因特網控制報文協議)、ARP協議(Address Resolution Protocol,地址解析協議)以及RARP協議(Reverse Address Resolution Protocol,逆地址解析協議)。網絡層重要的設備是路由器。常見的路由選擇協議有:RIP協議、OSPF協議。RIP協議 :底層是貝爾曼福特算法,它選擇路由的度量標準(metric)是跳數,最大跳數是15跳,如果大於15跳,它就會丟棄數據包;OSPF協議 :Open Shortest Path First開放式最短路徑優先,底層是迪傑斯特拉算法,是鏈路狀態路由選擇協議,它選擇路由的度量標準是帶寬,延遲。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

※教你寫出一流的銷售文案?

※回頭車貨運收費標準

※別再煩惱如何寫文案,掌握八大原則!

一個基於Consul的.NET Leader選舉類庫

前段時間有傳言說Consul將不能在我國繼續使用,后被查明是因法律問題Vault企業版產品不能在國內銷售。Valut和Consul都是HashiCorp公司的產品,並且都推出了開源版本,繼續使用開源版本都是沒有問題的,虛驚一場。Consul是一款優秀的服務發現和配置管理產品,基於其提供的Session機制,可以很方便的實現Leader選舉功能。這篇文章將介紹我編寫的一個基於Consul的.NET Leader選舉類庫。

基於Consul的Leader選舉原理

1、參加選舉的程序可以在Consul中創建一個Session,這個Session的存活狀態依賴於當前程序的Consul健康檢查狀態, 一旦健康檢查處於Critical狀態,則對應的Session就會失效。

2、使用這個Session去鎖定某個Consul Key/Value,只有一個Session能成功鎖住KV,擁有這個Session的程序即為Leader。

3、Leader選舉成功后,所有節點還要繼續阻塞查詢上邊的Consul Key/Value,如果KV綁定的Session失效了, 所有節點可以立即發現併發起一次Leader選舉,並選舉出1個Leader。

使用說明

1、啟動本機Consul

當前的版本依賴本機Consul,後續會支持配置遠程Consul地址。

如果本地環境已經配置Consul,保證其正常運行即可。

如果本地環境沒有配置Consul,可以下載后以開發模式快速啟動,以方便體驗Leader選舉功能。

下載地址:https://www.consul.io/downloads

啟動命令:./consul agent -dev

2、安裝Nuget包

NuGet包地址:https://www.nuget.org/packages/FireflySoft.LeaderElection

3、編寫Leader選舉代碼

首先創建LeaderElectionManager的一個實例,傳入服務名稱、服務Id、leader選舉選項等參數,然後調用Watch方法參与選舉,並在Watch方法中傳入Leader選舉結果的處理方法。

以控制台程序為例:

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("I am ElectionService1.");

            // 參与Leader選舉的多個程序應該使用相同的服務名
            // 參与Leader選舉的每個程序應該有唯一的服務Id
            LeaderElectionManager electionManager = new LeaderElectionManager("ElectionService", "ElectionService1", new LeaderElectionOptions());
            electionManager.Watch(LeaderElectCompletedEventHandler);

            Console.WriteLine("Start Election...");

            Console.Read();
        }

        private static void LeaderElectCompletedEventHandler(LeaderElectionResult result)
        {
            // 在這裏處理Leader選舉結果。
            Console.WriteLine($"LeaderElectCompleted, Result: {result.IsSuccess}, Current Leader: {result.State.CurrentLeaderId}.");
        }
    }

4、注意事項

選舉沉默期

LeaderElectionOptions中提供了一個重新選舉沉默期:ReElectionSilencePeriod,默認15s。應用場景如下:

當一個程序的Leader狀態失效時,它可能仍在處理某些事務,並且不能立即中止。 這時候如果其它節點馬上選舉成為Leader,並且開始處理數據,則可能導致數據不一致的狀態。

Leader優先選舉權

此類庫為Leader增加了優先選舉權。應用場景如下:

Leader狀態失效可能只是一種短暫的中斷導致的,系統會很快自動恢復,而業務事務的的啟動和中止需要進行複雜的處理, 所以我們仍然期望下一次Leader選舉時之前的Leader有優先選舉權,避免數據同步和加快系統恢復。

5、源碼開放

這麼好的東西當然要開源:https://github.com/bosima/FireflySoft.LeaderElection

參考文檔

1、Consul Session機制參考:

使用Consul做leader选举的方案

https://www.consul.io/docs/internals/sessions

2、基於Session的Leader選舉機制參考:

https://learn.hashicorp.com/consul/developer-configuration/elections

 

如果你有關於Consul的任何使用問題歡迎加入千人Consul QQ交流群:234939415

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※想知道最厲害的網頁設計公司"嚨底家"!

※別再煩惱如何寫文案,掌握八大原則!

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※回頭車貨運收費標準

台中搬家公司費用怎麼算?