標籤: 台北網頁設計

  • 數據結構之隊列and棧總結分析

    一、前言:

      數據結構中隊列和棧也是常見的兩個數據結構,隊列和棧在實際使用場景上也是相輔相成的,下面簡單總結一下,如有不對之處,多多指點交流,謝謝。

    二、隊列簡介

      隊列顧名思義就是排隊的意思,根據我們的實際生活不難理解,排隊就是有先後順序,先到先得,其實在程序數據結構中的隊列其效果也是一樣,及先進先出。

         隊列大概有如下一些特性:

         1、操作靈活,在初始化時不需要指定其長度,其長度自動增加(默認長度為32)

            注:在實際使用中,如果事先能夠預估其長度,那麼在初始化時指定長度,可以提高效率

            2、泛型的引入,隊列在定義時可以指定數據類型避免裝箱拆箱操作

         3、存儲數據滿足先進先出原則

           

       c#中有關隊列的幾個常用方法:

      • Count:Count屬性返回隊列中元素個數。
      • Enqueue:Enqueue()方法在隊列一端添加一個元素。
      • Dequeue:Dequeue()方法在隊列的頭部讀取和刪除元素。如果在調用Dequeue()方法時,隊列中不再有元素,就拋出一個InvalidOperationException類型的異常。
      • Peek:Peek()方法從隊列的頭部讀取一個元素,但不刪除它。
      • TrimExcess:TrimExcess()方法重新設置隊列的容量。Dequeue()方法從隊列中刪除元素,但它不會重新設置隊列的容量。要從隊列的頭部去除空元素,應使用TrimExcess()方法。
      • Clear:Clear()方法從隊列中移除所有的元素。
      • ToArray:ToArray()複製隊列到一個新的數組中。

      下面通過隊列來實例模擬消息隊列的實現流程:

     

    using System;
    using System.Collections;
    using System.Collections.Generic;
    
    namespace dataStructureQueueTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("通過Queue來模擬消息隊列的實現");
                QueueTest queueTest = new QueueTest();
    
                while (true)
                {
                    Console.WriteLine("請輸入你操作的類型:1:代表生成一條消息,2:代表消費一條消息");
                    string type = Console.ReadLine();
                    if (type == "1")
                    {
                        Console.WriteLine("請輸入具體消息:");
                        string inforValue = Console.ReadLine();
                        queueTest.InformationProducer(inforValue);
                    }
                    else if (type == "2")
                    {
                        //// 在消費消息的時候,模擬一下,消費成功與消費失敗下次繼續消費的場景
    
                        object inforValue = queueTest.InformationConsumerGet();
                        if (inforValue == null)
                        {
                            Console.WriteLine("當前無可消息可消費");
                        }
                        else
                        {
                            Console.WriteLine("獲取到的消息為:" + inforValue);
    
                            Console.WriteLine("請輸入消息消費結果:1:成功消費消息,2:消息消費失敗");
                            string consumerState = Console.ReadLine();
    
                            ///// 備註:該操作方式線程不安全,在多線程不要直接使用
                            if (consumerState == "1")
                            {
                                queueTest.InformationConsumerDel();
                            }
                        }
                    }
                    else
                    {
                        Console.WriteLine("操作有誤,請重新選擇");
                    }
                }
            }
        }
    
        /// <summary>
        /// 隊列練習
        /// </summary>
        public class QueueTest
        {
            /// <summary>
            /// 定義一個隊列
            /// </summary>
            public Queue<string> queue = new Queue<string>();
    
            /// <summary>
            /// 生成消息--入隊列
            /// </summary>
            /// <param name="inforValue"></param>
            public void InformationProducer(string inforValue)
            {
                queue.Enqueue(inforValue);
            }
    
            /// <summary>
            /// 消費消息---出隊列--只獲取數據,不刪除數據
            /// </summary>
            /// <returns></returns>
            public object InformationConsumerGet()
            {
                if (queue.Count > 0)
                {
                    return queue.Peek();
                }
    
                return null;
            }
    
            /// <summary>
            /// 消費消息---出隊列---獲取數據的同時刪除數據
            /// </summary>
            /// <returns></returns>
            public string InformationConsumerDel()
            {
                if (queue.Count > 0)
                {
                    return queue.Dequeue();
                }
    
                return null;
            }
        }
    }

     

     

    三、棧簡介

      棧和隊列在使用上很相似,只是棧的數據存儲滿足先進后出原則,棧有如下一些特性:

         1、操作靈活,在初始化時不需要指定其長度,其長度自動增加(默認長度為10)

            注:在實際使用中,如果事先能夠預估其長度,那麼在初始化時指定長度,可以提高效率

            2、泛型的引入,棧在定義時可以指定數據類型避免裝箱拆箱操作

         3、存儲數據滿足先進后出原則

        c#中有關棧的幾個常用方法:

    • Count:Count屬性返回棧中的元素個數。
    • Push:Push()方法在棧頂添加一個元素。
    • Pop:Pop()方法從棧頂刪除一個元素,並返回該元素。如果棧是空的,就拋出一個InvalidOperationException類型的異常。
    • Peek:Peek()方法返回棧頂的元素,但不刪除它。
    • Contains:Contains()方法確定某個元素是否在棧中,如果是,就返回true。

         下面通過一個棧來模擬瀏覽器的回退前進操作的實現

     

    using System;
    using System.Collections.Generic;
    
    namespace dataStructureStackTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                //// 通過棧來模擬瀏覽器回退前進操作
                ////   1、定義兩個棧,分別記錄回退的地址集合,和前進地址集合
                ////   2、在操作具體的回退或者前進操作時
                ////      如果和前一次操作相同,那麼就取出對應隊列的一條數據存儲到另外一個隊列
                Console.WriteLine("本練習模擬瀏覽器的回退前進操作:");
    
                /// 假設瀏覽器已瀏覽了20個網站記錄
                StackTest stackTestBack = new StackTest(20);
                StackTest stackTestGo = new StackTest(20);
                for (int i = 0; i < 20; i++)
                {
                    stackTestBack.PushStack("網站" + (i + 1).ToString());
                }
    
                //// 記錄上一次操作
                string beforOpert = "";
                while (true)
                {
                    Console.WriteLine("");
                    Console.WriteLine("請輸入你操作的類型:1:回退,2:前進");
                    string type = Console.ReadLine();
    
                    if (type == "1")
                    {
                        //// 出棧
                        if (beforOpert == type)
                        {
                            stackTestGo.PushStack(stackTestBack.GetAndDelStack());
                        }
                        string wbeSit = stackTestBack.GetStack();
                        Console.WriteLine("回退到頁面:" + wbeSit);
                        beforOpert = type;
                    }
                    else if (type == "2")
                    {
                        //// 出棧
                        if (beforOpert == type)
                        {
                            stackTestBack.PushStack(stackTestGo.GetAndDelStack());
                        }
                        string wbeSit = stackTestGo.GetStack();
    
                        Console.WriteLine("回退到頁面:" + wbeSit);
                        beforOpert = type;
                    }
                    else
                    {
                        Console.WriteLine("請輸入正確的操作方式!!");
                    }
                }
            }
        }
    
        /// <summary>
        /// 隊列練習
        /// </summary>
        public class StackTest
        {
            /// <summary>
            /// 定義一個棧
            /// </summary>
            public Stack<string> stack;
    
            /// <summary>
            ///無參數構造函數,棧初始化為默認長度
            /// </summary>
            public StackTest()
            {
                stack = new Stack<string>();
            }
    
            /// <summary>
            ///有參數構造函數,棧初始化為指定長度
            ///如果在定義隊列時,如果知道需要存儲的數據長度,那麼最好預估一個長度,並初始化指定的長度
            /// </summary>
            public StackTest(int stackLen)
            {
                stack = stackLen > 0 ? new Stack<string>(stackLen) : new Stack<string>();
            }
    
            /// <summary>
            /// 入棧
            /// </summary>
            /// <param name="inforValue"></param>
            public void PushStack(string inforValue)
            {
                stack.Push(inforValue);
            }
    
            /// <summary>
            /// 出棧(但不刪除)
            /// </summary>
            /// <returns></returns>
            public string GetStack()
            {
                if (stack.Count > 0)
                {
                    return stack.Peek();
                }
    
                return null;
            }
    
            /// <summary>
            /// 出棧(並刪除)
            /// </summary>
            /// <returns></returns>
            public string GetAndDelStack()
            {
                if (stack.Count > 0)
                {
                    return stack.Pop();
                }
    
                return null;
            }
        }
    }

     

    四、使用場景總結

      根據隊列和棧的特點,下面簡單總結一下隊列和棧的一些實際使用場景

       隊列:

        1、異步記錄日誌,此處會涉及到單例模式的使用

        2、消息隊列

        3、業務排隊,比如12306車票購買排隊等候

        4、其他符合先進先出原則的業務操作

       棧:

        1、可回退的操作記錄,比如:瀏覽器的回退操作

        2、計算表達式匹配,比如:計算器表達式計算

        3、其他符合先進后出原則的業務操作

     

    附件:

    關於這一些練習的代碼,上傳到github,有興趣的可以看一下:

     

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

    【其他文章推薦】

    USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

    ※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

    ※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

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

  • 徹底搞懂 netty 線程模型

    徹底搞懂 netty 線程模型

    編者注:Netty是Java領域有名的開源網絡庫,特點是高性能和高擴展性,因此很多流行的框架都是基於它來構建的,比如我們熟知的Dubbo、Rocketmq、Hadoop等。本文就netty線程模型展開分析討論下 : )

    IO模型

    • BIO:同步阻塞IO模型;
    • NIO:基於IO多路復用技術的“非阻塞同步”IO模型。簡單來說,內核將可讀可寫事件通知應用,由應用主動發起讀寫操作;
    • AIO:非阻塞異步IO模型。簡單來說,內核將讀完成事件通知應用,讀操作由內核完成,應用只需操作數據即可;應用做異步寫操作時立即返回,內核會進行寫操作排隊並執行寫操作。

    NIO和AIO不同之處在於應用是否進行真正的讀寫操作。

    reactor和proactor模型

    • reactor:基於NIO技術,可讀可寫時通知應用;
    • proactor:基於AIO技術,讀完成時通知應用,寫操作應用通知內核。

    netty線程模型

    netty的線程模型是基於Reactor模型的。

    netty單線程模型

    Reactor 單線程模型,是指所有的 I/O 操作都在同一個 NIO 線程上面完成的,此時NIO線程職責包括:接收新建連接請求、讀寫操作等。

    在一些小容量應用場景下,可以使用單線程模型(注意,Redis的請求處理也是單線程模型,為什麼Redis的性能會如此之高呢?因為Redis的讀寫操作基本都是內存操作,並且Redis協議比較簡潔,序列化/反序列化耗費性能更低)。但是對於高負載、大併發的應用場景卻不合適,主要原因如下:

    • 一個NIO線程同時處理成百上千的連接,性能上無法支撐,即便NIO線程的CPU負荷達到100%,也無法滿足海量消息的編碼、解碼、讀取和發送。
    • 當NIO線程負載過重之後,處理速度將變慢,這會導致大量客戶端連接超時,超時之後往往會進行重發,這更加重了NIO線程的負載,最終會導致大量消息積壓和處理超時,成為系統的性能瓶頸。
    • 可靠性問題:一旦NIO線程意外跑飛,或者進入死循環,會導致整個系統通信模塊不可用,不能接收和處理外部消息,造成節點故障。

    Reactor多線程模型

    Rector 多線程模型與單線程模型最大的區別就是有一組 NIO 線程來處理連接讀寫操作,一個NIO線程處理Accept。一個NIO線程可以處理多個連接事件,一個連接的事件只能屬於一個NIO線程。

    在絕大多數場景下,Reactor 多線程模型可以滿足性能需求。但是,在個別特殊場景中,一個 NIO 線程負責監聽和處理所有的客戶端連接可能會存在性能問題。例如併發百萬客戶端連接,或者服務端需要對客戶端握手進行安全認證,但是認證本身非常損耗性能。在這類場景下,單獨一個 Acceptor 線程可能會存在性能不足的問題,為了解決性能問題,產生了第三種 Reactor 線程模型——主從Reactor 多線程模型。

    Reactor主從多線程模型

    主從 Reactor 線程模型的特點是:服務端用於接收客戶端連接的不再是一個單獨的 NIO 線程,而是一個獨立的 NIO 線程池。Acceptor 接收到客戶端 TCP連接請求並處理完成后(可能包含接入認證等),將新創建的 SocketChannel注 冊 到 I/O 線 程 池(sub reactor 線 程 池)的某個I/O線程上, 由它負責SocketChannel 的讀寫和編解碼工作。Acceptor 線程池僅僅用於客戶端的登錄、握手和安全認證,一旦鏈路建立成功,就將鏈路註冊到後端 subReactor 線程池的 I/O 線程上,由 I/O 線程負責後續的 I/O 操作。

    netty線程模型思考

    netty 的線程模型並不是一成不變的,它實際取決於用戶的啟動參數配置。通過設置不同的啟動參數,Netty 可以同時支持 Reactor 單線程模型、多線程模型。

    為了盡可能地提升性能,Netty 在很多地方進行了無鎖化的設計,例如在 I/O 線程內部進行串行操作,避免多線程競爭導致的性能下降問題。表面上看,串行化設計似乎 CPU 利用率不高,併發程度不夠。但是,通過調整 NIO 線程池的線程參數,可以同時啟動多個串行化的線程并行運行,這種局部無鎖化的串行線程設計相比一個隊列多個工作線程的模型性能更優。(小夥伴們後續多線程併發流程可參考該類實現方案

    Netty 的 NioEventLoop 讀取到消息之後,直接調用 ChannelPipeline 的fireChannelRead (Object msg)。 只要用戶不主動切換線程, 一直都是由NioEventLoop 調用用戶的 ChannelHandler,期間不進行線程切換。這種串行化處理方式避免了多線程操作導致的鎖的競爭,從性能角度看是最優的。

    Netty擁有兩個NIO線程池,分別是bossGroupworkerGroup,前者處理新建連接請求,然後將新建立的連接輪詢交給workerGroup中的其中一個NioEventLoop來處理,後續該連接上的讀寫操作都是由同一個NioEventLoop來處理。注意,雖然bossGroup也能指定多個NioEventLoop(一個NioEventLoop對應一個線程),但是默認情況下只會有一個線程,因為一般情況下應用程序只會使用一個對外監聽端口。

    這裏試想一下,難道不能使用多線程來監聽同一個對外端口么,即多線程epoll_wait到同一個epoll實例上?

    epoll相關的主要兩個方法是epoll_wait和epoll_ctl,多線程同時操作同一個epoll實例,那麼首先需要確認epoll相關方法是否線程安全:簡單來說,epoll是通過鎖來保證線程安全的, epoll中粒度最小的自旋鎖ep->lock(spinlock)用來保護就緒的隊列, 互斥鎖ep->mtx用來保護epoll的重要數據結構紅黑樹

    看到這裏,可能有的小夥伴想到了Nginx多進程針對監聽端口的處理策略,Nginx是通過accept_mutex機制來保證的。accept_mutex是nginx的(新建連接)負載均衡鎖,讓多個worker進程輪流處理與client的新連接。當某個worker進程的連接數達到worker_connections配置(單個worker進程的最大處理連接數)的最大連接數的7/8時,會大大減小獲取該worker獲取accept鎖的概率,以此實現各worker進程間的連接數的負載均衡。accept鎖默認打開,關閉它時nginx處理新建連接耗時會更短,但是worker進程之間可能連接不均衡,並且存在“驚群”問題。只有在使能accept_mutex並且當前系統不支持原子鎖時,才會用文件實現accept鎖。注意,accept_mutex加鎖失敗時不會阻塞當前線程,類似tryLock。

    現代linux中,多個socker同時監聽同一個端口也是可行的,nginx 1.9.1也支持這一行為。linux 3.9以上內核支持SO_REUSEPORT選項,允許多個socker bind/listen在同一端口上。這樣,多個進程可以各自申請socker監聽同一端口,當連接事件來臨時,內核做負載均衡,喚醒監聽的其中一個進程來處理,reuseport機制有效的解決了epoll驚群問題。

    再回到剛才提出的問題,java中多線程來監聽同一個對外端口,epoll方法是線程安全的,這樣就可以使用使用多線程監聽epoll_wait了么,當然是不建議這樣乾的,除了epoll的驚群問題之外,還有一個就是,一般開發中我們使用epoll設置的是LT模式(水平觸發方式,與之相對的是ET默認,前者只要連接事件未被處理就會在epoll_wait時始終觸發,後者只會在真正有事件來時在epoll_wait觸發一次),這樣的話,多線程epoll_wait時就會導致第一個線程epoll_wait之後還未處理完畢已發生的事件時,第二個線程也會epoll_wait返回,顯然這不是我們想要的,關於java nio的測試demo如下:

    public class NioDemo {
        private static AtomicBoolean flag = new AtomicBoolean(true);
        public static void main(String[] args) throws Exception {
            ServerSocketChannel serverChannel = ServerSocketChannel.open();
            serverChannel.socket().bind(new InetSocketAddress(8080));
            // non-block io
            serverChannel.configureBlocking(false);
            Selector selector = Selector.open();
            serverChannel.register(selector, SelectionKey.OP_ACCEPT);
    
            // 多線程執行
            Runnable task = () -> {
                try {
                    while (true) {
                        if (selector.select(0) == 0) {
                            System.out.println("selector.select loop... " + Thread.currentThread().getName());
                            Thread.sleep(1);
                            continue;
                        }
    
                        if (flag.compareAndSet(true, false)) {
                            System.out.println(Thread.currentThread().getName() + " over");
                            return;
                        }
    
                        Iterator<SelectionKey> iter = selector.selectedKeys().iterator();
                        while (iter.hasNext()) {
                            SelectionKey key = iter.next();
    
                            // accept event
                            if (key.isAcceptable()) {
                                handlerAccept(selector, key);
                            }
    
                            // socket event
                            if (key.isReadable()) {
                                handlerRead(key);
                            }
    
                            /**
                             * Selector不會自己從已選擇鍵集中移除SelectionKey實例,必須在處理完通道時手動移除。
                             * 下次該通道變成就緒時,Selector會再次將其放入已選擇鍵集中。
                             */
                            iter.remove();
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            };
    
            List<Thread> threadList = new ArrayList<>();
            for (int i = 0; i < 2; i++) {
                Thread thread = new Thread(task);
                threadList.add(thread);
                thread.start();
            }
            for (Thread thread : threadList) {
                thread.join();
            }
            System.out.println("main end");
        }
    
        static void handlerAccept(Selector selector, SelectionKey key) throws Exception {
            System.out.println("coming a new client... " + Thread.currentThread().getName());
            Thread.sleep(10000);
            SocketChannel channel = ((ServerSocketChannel) key.channel()).accept();
            channel.configureBlocking(false);
            channel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));
        }
    
        static void handlerRead(SelectionKey key) throws Exception {
            SocketChannel channel = (SocketChannel) key.channel();
            ByteBuffer buffer = (ByteBuffer) key.attachment();
            buffer.clear();
    
            int num = channel.read(buffer);
            if (num <= 0) {
                // error or fin
                System.out.println("close " + channel.getRemoteAddress());
                channel.close();
            } else {
                buffer.flip();
                String recv = Charset.forName("UTF-8").newDecoder().decode(buffer).toString();
                System.out.println("recv: " + recv);
    
                buffer = ByteBuffer.wrap(("server: " + recv).getBytes());
                channel.write(buffer);
            }
        }
    }

    netty線程模型實踐

    (1) 時間可控的簡單業務直接在 I/O 線程上處理

    時間可控的簡單業務直接在 I/O 線程上處理,如果業務非常簡單,執行時間非常短,不需要與外部網絡交互、訪問數據庫和磁盤,不需要等待其它資源,則建議直接在業務 ChannelHandler 中執行,不需要再啟業務的線程或者線程池。避免線程上下文切換,也不存在線程併發問題。

    (2) 複雜和時間不可控業務建議投遞到後端業務線程池統一處理

    複雜度較高或者時間不可控業務建議投遞到後端業務線程池統一處理,對於此類業務,不建議直接在業務 ChannelHandler 中啟動線程或者線程池處理,建議將不同的業務統一封裝成 Task,統一投遞到後端的業務線程池中進行處理。過多的業務ChannelHandler 會帶來開發效率和可維護性問題,不要把 Netty 當作業務容器,對於大多數複雜的業務產品,仍然需要集成或者開發自己的業務容器,做好和Netty 的架構分層。

    (3) 業務線程避免直接操作 ChannelHandler

    業務線程避免直接操作 ChannelHandler,對於 ChannelHandler,IO 線程和業務線程都可能會操作,因為業務通常是多線程模型,這樣就會存在多線程操作ChannelHandler。為了盡量避免多線程併發問題,建議按照 Netty 自身的做法,通過將操作封裝成獨立的 Task 由 NioEventLoop 統一執行,而不是業務線程直接操作,相關代碼如下所示:

    如果你確認併發訪問的數據或者併發操作是安全的,則無需多此一舉,這個需要根據具體的業務場景進行判斷,靈活處理。

    推薦閱讀

    歡迎小夥伴關注【TopCoder】閱讀更多精彩好文。

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

    【其他文章推薦】

    ※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

    ※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

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

    ※帶您來看台北網站建置台北網頁設計,各種案例分享

  • 吉利:到2020年新能源汽車銷量將實現90%以上的占比

    日前,吉利控股集團董事長李書福在接受《中國經營報》記者採訪時表示,以後我們開發的新產品基本是新能源汽車和智慧互聯汽車,傳統汽車就逐漸不生產了。

    此話背後,實際就是吉利於近日提出的“藍色吉利行動”中的重要一環,到2020年,其新能源汽車銷量將實現90%以上的銷量占比。

    具體來說,根據“藍色吉利行動”,吉利新能源將在技術上主打純電動、油電混動、插電式混合動力三種路線,並通過兩大平臺——FE(中高端)與PE(緊湊級)平臺來發展純電動車板塊。

    從以上路徑上看,吉利與其他車企並無二致,但其公佈的“五大承諾”卻足以讓業內熱議——第一,提前全面實現2020年國家第四階段每百公里5.0L的企業平均燃油消耗限值;第二,實現消費者用傳統汽車的購買成本購買插電式混動汽車的夢想;第三,實現到2020年新能源汽車銷量占吉利整體銷量的90%以上;第四,在氫燃料及金屬燃料電池汽車研發方面取得實質性成果;第五,實現新能源技術,智慧化、輕量化技術在行業的領先地位。

    雖然言之鑿鑿,但不得不說的是,90%以上的新能源銷量加上此前吉利發佈的“2020年實現120萬輛”的銷量目標,同年吉利新能源汽車銷量目標竟逾100萬輛。

    對此,吉利控股集團總裁CEO安聰慧表示:“吉利制定這樣的目標並不是為了和其他企業進行對比,而是結合自身發展提出來的。”

    據其介紹,在技術領域,吉利汽車將以與沃爾沃合作打造的CMA中高級車基礎模組架構為核心打造新能源車型,該方面的設計研發工作主要由吉利汽車歐洲研發中心承擔,該中心在瑞典哥德堡已有1200名工程師,中國杭州也有300名工程師,負責架構開發、上車體開發、核心部件開發開發,整車設計、工程製造及新技術的研發。CMA基礎模組架構可以實現電機+發動機等核心部件的批量生產。

    此外,2015年初,吉利與新大洋機電集團成立合資公司並推出知豆電動車,加之此前其子公司上海華普國潤與康迪車業成立的合資公司,署名吉利旗下的新能源車型並不止吉利品牌。雖然,吉利在新能源領域的開疆破土頗有“借力而為”之感,但不論如何,2015年1~11月,在乘聯會統計的自主品牌新能源車銷量占比情況中,吉利節節攀升,的確實現了在自主品牌領域的市占率穩增,也正因如此,加之政策的多重鼓勵,吉利才許下到2020年實現新能源汽車逾百萬的戰略目標。

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

    ※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

    ※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

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

  • 北汽豪擲80億元佈局新能源汽車

    2015年12月28日,北京汽車集團有限公司就“北汽新能源汽車動力電池”、“北汽集團常州產業基地”兩個專案,與常州市政府簽約。

    此次北汽集團擬在常州建設的兩個項目總投資80億元,其中,北汽新能源汽車動力電池專案總投資約30億元,規劃動力電池產能達到5G瓦時,同時將以滆湖低碳濕地公園培訓中心為主體,打造北汽新能源綠色商學院,其主要目的是加強新體系電池基礎研究和關鍵技術開發,推進新一代鋰離子電池的工程化和產業化,實現對動力電池產業鏈核心環節資源掌控,以支撐北汽新能源業務需求。

    而北汽集團常州產業基地專案總投資50億元,總規劃年產30萬輛整車及配套零部件、物流專案,其中一期年產15萬輛SUV、MPV和輕型客車,二期重點生產新能源汽車,打造產業生態鏈。

    此前,北汽集團總投資100億元的新能源汽車和總投資50億元的通用航空兩個項目已經於今年4月和10月相繼落戶常州。

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

    ※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

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

    ※帶您來看台北網站建置台北網頁設計,各種案例分享

  • 源碼學習系列之SpringBoot自動配置(篇二)

    源碼學習系列之SpringBoot自動配置(篇二)

    源碼學習系列之SpringBoot自動配置(篇二)之HttpEncodingAutoConfiguration 源碼分析

    繼上一篇博客之後,本博客繼續跟一下SpringBoot的自動配置源碼

    ok,先複習一下上一篇的內容,從前面的學習,我們知道了SpringBoot的自動配置主要是由一個選擇器AutoConfigurationImportSelector,先通過選擇器將自動配置的類加載到Spring容器

    注意點:

    • List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);獲取的候選配置的類名
    • 由SpringFactoriesLoader加載器負責加載配置類名,已經裝載配置類到容器,SpringFactoriesLoader的loadSpringFactories方法讀取自動配置工程的META-INF/spring.factories配置文件,加載配置類的全類名,包裝成Properties對象,然後再加載到容器里
    public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
        /* 將spring.factories的類都裝載到Spring容器*/
         public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
            String factoryClassName = factoryClass.getName();
    
            try {
            //將META-INF/spring.factories文件里配置的屬性都裝載到Enumeration數據結構里
                Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                ArrayList result = new ArrayList();
                //遍歷獲取屬性,然後再獲取對應的配置類全類名
                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
                    String factoryClassNames = properties.getProperty(factoryClassName);
                    result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
                }
    
                return result;
            } catch (IOException var8) {
                throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + "META-INF/spring.factories" + "]", var8);
            }
        }
    

    ok,Springboot的自動配置類都在這個包里,源碼很多,所以本博客只是簡單跟一下源碼

    自動配置可以說是SpringBoot框架的一個很重要的功能,其強大的功能就是通過很多配置類實現的,當然這麼多配置,可以參考SpringBoot官方的配置參考:
    https://docs.spring.io/spring-boot/docs/2.1.10.RELEASE/reference/html/common-application-properties.html

    SpringBoot的自動配置類很多,顯然不是每個配置類都生效的,比如你沒引對應的jar,那對應的配置類肯定是不起效的,ok,本博客以HttpEncodingAutoConfiguration自動編碼配置類為實例,記錄一下SpringBoot的自動配置

    先補充一些@Conditional註解的用法:詳情可以參考我上篇博客

    @Conditional派生註解 作用(都是判斷是否符合指定的條件)
    @ConditionalOnJava 系統的java版本是否符合要求
    @ConditionalOnBean 有指定的Bean類
    @ConditionalOnMissingBean 沒有指定的bean類
    @ConditionalOnExpression 符合指定的SpEL表達式
    @ConditionalOnClass 有指定的類
    @ConditionalOnMissingClass 沒有指定的類
    @ConditionalOnSingleCandidate 容器只有一個指定的bean,或者這個bean是首選bean
    @ConditionalOnProperty 指定的property屬性有指定的值
    @ConditionalOnResource 路徑下存在指定的資源
    @ConditionalOnWebApplication 系統環境是web環境
    @ConditionalOnNotWebApplication 系統環境不是web環境
    @ConditionalOnjndi JNDI存在指定的項

    通過上篇博客的學習,我們已經知道了SpringBoot有很多自動配置類,所以本博客拿HttpEncodingAutoConfiguration類來看看

    補充:

    • @Configuration proxyBeanMethods屬性:默認是開啟的,開啟后允許其它配置類調用這個類的@bean方法,詳情參看Spring官方文檔:
    package org.springframework.boot.autoconfigure.web.servlet;
    
    import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
    import org.springframework.boot.autoconfigure.http.HttpProperties;
    import org.springframework.boot.autoconfigure.http.HttpProperties.Encoding;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.boot.web.server.WebServerFactoryCustomizer;
    import org.springframework.boot.web.servlet.filter.OrderedCharacterEncodingFilter;
    import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.Ordered;
    import org.springframework.web.filter.CharacterEncodingFilter;
    
    @Configuration(
        proxyBeanMethods = false
    )//指定是一個配置列,關了proxyBeanMethods,其它配置類就不能調相應的@bean類
    @EnableConfigurationProperties({HttpProperties.class})//讓使用 @ConfigurationProperties註解的HttpProperties類生效,HttpProperties類通過ConfigurationProperties註解,將屬性配置一個一個加載進來
    @ConditionalOnWebApplication(
        type = Type.SERVLET
    )//指定系統環境是Web環境配置才起效,並且指定類型是SERVLET
    @ConditionalOnClass({CharacterEncodingFilter.class})//系統有CharacterEncodingFilter過濾器類,則配置類起效,CharacterEncodingFilter類:SpringMVC中進行亂碼解決的過濾器
    @ConditionalOnProperty(
        prefix = "spring.http.encoding",
        value = {"enabled"},
        matchIfMissing = true
    )//判斷配置文件是否有spring.http.encoding.enabled屬性,如果沒配置,也是默認為true的,因為配置了`matchIfMissing =true`
    public class HttpEncodingAutoConfiguration {
        //創建一個Encoding對象
        private final Encoding properties;
        // 構造函數里通過properties.getEncoding();進行屬性映射,獲取默認的配置
        public HttpEncodingAutoConfiguration(HttpProperties properties) {
            this.properties = properties.getEncoding();
        }
    
        @Bean
        @ConditionalOnMissingBean//如果系統沒有CharacterEncodingFilter類,就執行characterEncodingFilter方法
        public CharacterEncodingFilter characterEncodingFilter() {
            //重新創建一個編碼過濾器
            OrderedCharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
            //設置默認的配置
            filter.setEncoding(this.properties.getCharset().name());
            filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST));
            filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE));
            return filter;
        }
    
        @Bean
        public HttpEncodingAutoConfiguration.LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {
            return new HttpEncodingAutoConfiguration.LocaleCharsetMappingsCustomizer(this.properties);
        }
    
        private static class LocaleCharsetMappingsCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {
            private final Encoding properties;
    
            LocaleCharsetMappingsCustomizer(Encoding properties) {
                this.properties = properties;
            }
    
            public void customize(ConfigurableServletWebServerFactory factory) {
                if(this.properties.getMapping() != null) {
                    factory.setLocaleCharsetMappings(this.properties.getMapping());
                }
    
            }
    
            public int getOrder() {
                return 0;
            }
        }
    }
    

    通過對HttpEncodingAutoConfiguration源碼的學習,可以看出,其實主要是用@Conditional及其派生註解,這些註解都是要在特定情況才會起效,起效了,才會將組件加載到Spring容器里

    ok,然後我們怎麼知道哪些配置是起效的?在SpringBoot項目里,是可以通過配置,開啟打印的,可以在application.properties加上debug=true屬性就可以

    控制台打印的Positive matches就表示有效的配置類

    console打印的Negative matches表示不起效的配置類:
    比如我的項目沒有加aop的,aop自動配置類就不起效

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

    【其他文章推薦】

    USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

    ※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

    ※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

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

  • 代碼注入及其拓展–逆向開發

    代碼注入及其拓展–逆向開發

    今天繼續講述逆向開發中另一個比較重要的課程是代碼注入內容,本篇篇幅比較長,但還是有很多乾貨的,希望大家通過此篇文章更加了解逆向開發中的要點和知識點.我們將分解幾個內容,進行講解:

    1. Framework注入
    2. Dylib注入
    3. MethodSwizzle
    4. 微信示例講解
    5. 總結

    讓代碼執行自己的代碼,整體方案如下:

    如何讓別人的app來執行自己的代碼呢? 這就要通過代碼注入的方式來達到,而代碼注入的方式有兩種: 一種是通過framework, 一種是dylib方式,另種方案,可以通過Runtime機制

    代碼注入思路:

    DYLD會動態加載動態庫Framework中所有動態庫,在frameworks中加入自己的一個動態庫,然後在動態庫中hook和注入代碼.

    一、FrameWork注入

     1.準備工作

    • 微信6.6.5(越獄應用)
    • MachOView軟件

      MachOView的下載地址:

      如果想看源碼如下:MachOView源碼:

    • yololib工具(給MachOView注入framework)

      yololib工具下載地址:

    • 簽名文件appsign文件

    2.流程

    2.1 加入準備工作,導入微信6.6.5版本以及腳本appSign.sh重簽名文件

    2.2 將appSign導入到項目腳本中

     

     

     2.3 有了上面的兩個步驟后,然後編譯一下工程,會出現一個temp工程,裡面包含了payload文件

    2.4 显示包內容,查看可執行文件

     2.5 我們通過MachOView軟件查看WeChat

    我們看到有很多的DYLIB,代表的是加載動態庫

    2.6  我們在項目中新建framework

     

    2.7 新建文件用於驗證

    2.8 想要達到剛加載就運行,代碼要寫在load方法

     2.9 編譯一下,查看app包位置會多出一個framework

    2.10 显示包內容,在framework查看

    由上可知,WJHookFrameWork已經加入成功。

    2.11 但是運行並沒有成功,沒有執行load里的代碼

    原因:用MachOView打開可執行的WeChat,沒有找到WJHookFrameWork

    下面我們講述怎麼將WJHookFramework寫入到MachoView文件中?

    3. WJHookFramework寫入到MachOView文件中

    需要使用yololib工具,建議將yololib放到 /usr/local/bin

    3.1 解壓越獄包

    3.2 將WeChat.app显示包內容,找到WeChat可執行的文件

    需要增加執行權限: chmod +x WeChat

    3.3 寫入WeChat可執行文件

    yololib WeChat Frameworks/WJHookFrameWork.framework/WJHookFrameWork

    通過上面的過程,查看MachOView文件Load commands中是否有WJHookFrameWork

    上面圖显示已經加入成功。

    3.4 刪除原有的ipa,打包payload

    zip -ry WeChat.ipa Payload

    將WeChat.ipa放入App目錄中,刪除其他的文件夾。

     

    3.5 再次運行,發現成功!!!

    上面就是framework方式代碼注入。大家可以私信我,如有不懂!!!

     二、Dylib注入

    2.1 新建工程,添加腳本到build phases 


    加入腳本文件

    2.2添加第三方庫dylib(mac os的,非ios)

    2.3 添加依賴

    2.4 修改第三方類庫僅限mac使用,修改Base SDK

    2.5 修改signing 

    2.6 腳本中注入動態庫的代碼

    # ${SRCROOT} 它是工程文件所在的目錄
    TEMP_PATH="${SRCROOT}/Temp"
    #資源文件夾,我們提前在工程目錄下新建一個APP文件夾,裏面放ipa包
    ASSETS_PATH="${SRCROOT}/APP"
    #目標ipa包路徑
    TARGET_IPA_PATH="${ASSETS_PATH}/*.ipa"
    #清空Temp文件夾
    rm -rf "${SRCROOT}/Temp"
    mkdir -p "${SRCROOT}/Temp"
    
    #----------------------------------------
    # 1. 解壓IPA到Temp下
    unzip -oqq "$TARGET_IPA_PATH" -d "$TEMP_PATH"
    # 拿到解壓的臨時的APP的路徑
    TEMP_APP_PATH=$(set -- "$TEMP_PATH/Payload/"*.app;echo "$1")
    # echo "路徑是:$TEMP_APP_PATH"
    
    #----------------------------------------
    # 2. 將解壓出來的.app拷貝進入工程下
    # BUILT_PRODUCTS_DIR 工程生成的APP包的路徑
    # TARGET_NAME target名稱
    TARGET_APP_PATH="$BUILT_PRODUCTS_DIR/$TARGET_NAME.app"
    echo "app路徑:$TARGET_APP_PATH"
    
    rm -rf "$TARGET_APP_PATH"
    mkdir -p "$TARGET_APP_PATH"
    cp -rf "$TEMP_APP_PATH/" "$TARGET_APP_PATH"
    
    #----------------------------------------
    # 3. 刪除extension和WatchAPP.個人證書沒法簽名Extention
    rm -rf "$TARGET_APP_PATH/PlugIns"
    rm -rf "$TARGET_APP_PATH/Watch"
    
    #----------------------------------------
    # 4. 更新info.plist文件 CFBundleIdentifier
    #  設置:"Set : KEY Value" "目標文件路徑"
    /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $PRODUCT_BUNDLE_IDENTIFIER" "$TARGET_APP_PATH/Info.plist"
    
    #----------------------------------------
    # 5. 給MachO文件上執行權限
    # 拿到MachO文件的路徑
    APP_BINARY=`plutil -convert xml1 -o - $TARGET_APP_PATH/Info.plist|grep -A1 Exec|tail -n1|cut -f2 -d\>|cut -f1 -d\<`
    #上可執行權限
    chmod +x "$TARGET_APP_PATH/$APP_BINARY"
    
    #----------------------------------------
    # 6. 重簽名第三方 FrameWorks
    TARGET_APP_FRAMEWORKS_PATH="$TARGET_APP_PATH/Frameworks"
    if [ -d "$TARGET_APP_FRAMEWORKS_PATH" ];
    then
    for FRAMEWORK in "$TARGET_APP_FRAMEWORKS_PATH/"*
    do
    
    #簽名
    /usr/bin/codesign --force --sign "$EXPANDED_CODE_SIGN_IDENTITY" "$FRAMEWORK"
    done
    fi
    
    #注入
    yololib "$TARGET_APP_PATH/$APP_BINARY" "Frameworks/libHankHook.dylib"

    2.7 編譯運行成功(也和上面一樣在類中加入load代碼)

     

    上面就是dylib方式代碼注入,希望對大家有所幫助!!!

     通過上面的兩種方式實現代碼注入,讓別人的app運行自己的app,下面總結如下:

     三、MethodSwizzle

    3.1 概念

    iOS 中實現AOP編程思想的方式其中之一是Method Swizzling,而 Method Swizzling 是利用Runtime特性把一個方法和另個方法的實現做替換,程序運行時修改Dispatch Table里SEL和IMP之間的映射關係.

    通過swizzling method改變目標函數selector所指向實現,在新的實現中來實現所要改的內容即可.

    3.2 特點

    • 繼承: 修改較多,無法敢保證他人一定繼承基類
    • 類別: 類別中重寫方法會覆蓋到原有的實現,其實,在真實的開發中,重寫方法並不是為了取代它,而是為了添加一些實現; 如果幾個類別實現了同樣的方法, 但只有一個類別的方法會被調用.
    • AOP優勢: 減少了重複代碼

    3.3 代碼

    @implementation NSURL (HKURL)
    
    +(void)load
    {
        Method URLWithStr = class_getClassMethod(self, @selector(URLWithString:));
        
        Method HKURL = class_getClassMethod(self, @selector(HKURLWithStr:));
        
        //交換
        method_exchangeImplementations(URLWithStr, HKURL);
    }
    
    +(instancetype)HKURLWithStr:(NSString *)str{
        //調用系統原來的方法
        NSURL * url = [NSURL HKURLWithStr:str];
        if (url == nil) {
            str = @"https://www.blog.com";
        }
        url = [NSURL HKURLWithStr:str];
        
        return url;
    }

    在上面的代碼中,利用method swizzling的交換方法.其他Runtime的使用方法,以及為什麼寫在load方法中,請參考本人另篇博客

    拓展: 為什麼寫在load中?

    • load方法在源文件被裝載到程序中會被自動調用,不需要手動調用,也不需要該類使用不使用無關,在main()前被執行.
    • 當子類重寫了load,假如子類的類別重寫了load,load的調用順序會這樣: 父類、子類、子類類別
    • 但是如果有多個子類category都重寫了load,每個子類category中load都會調用一次
    • 假如子類沒有重寫load,子類的默認load也不會去調用父類的load.此與正常繼承不太一樣.
    • 在正常的開發中, 除了method swizzle ,其他的邏輯代碼盡量不放在load,load方法中的代碼邏輯要盡量簡單

     

    四、微信示例Demo

    4.1 微信–破壞註冊

    4.1.1 將微信程序運行出來,如下圖所示

    4.1.2 根據上面紅色找出類名,方法名

    4.1.3 通過插件class-dump導出微信的.h文件

    class-dump是將OC運行時聲明的信息導出來的工具, 其實可以導出.h文件. 用此工具將未經過加密的app的頭文件導出來.

    使用它同樣也要講此工具拷貝到MAC的目錄下/usr/local/bin下.

    4.1.4 經過sublime text來找出對應的文件

    4.1.5 通過第三部分講解,利用runtime交換方法

    4.1.6 結果

     

    4.2 竊取微信密碼

    4.2.1 找到輸入密碼框的內容

    從上面看出,登錄按鈕為一個FixTitleColorButton對象,Target名字存放的地址為0x280afaa40,Action名字存放地址是0x280afac00。

    4.2.2 查看賬號密碼的輸入框

    發現賬號密碼輸入框對象屬於都一個對象,叫做WCUITextField

    4.2.3 利用LLDB查看登錄具體的Target和Action

    從上面卡出,登錄按鈕在WCAccountMainLoginViewController頁面中;

    登錄點擊方法叫做onNext

    4.2.4 利用Sublime查看WeChat文件

    發現確實有onNext()方法,並從中看出賬號輸入框和密碼輸入框都是WCAccountTextFieldItem中,但是並沒有發現textFileld,但是可以看到WCAccountTextFieldItem是繼承於WCBaseTextFieldItem,我們再看看WCBaseTextFieldItem文件內容

    看出一個m_textField對象,通過tex字段取出string。

    4.2.5 在賬號欄中輸入賬號和密碼

    po [(WCAccountMainLoginViewController *)0x1128bbc00 valueForKey:@"_textFieldUserPwdItem"]
    po [(WCAccountTextFieldItem *)0x28328e880 valueForKey:@"m_textField"]
    po [(WCUITextField *)0x112163a00 text]

    通過LLDB調試輸入的密碼是123456。

    4.2.6 Hook登錄,獲取密碼

    + (void)load {
        NSLog(@"來了,老弟");
        Method onNext = class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), sel_registerName("onNext"));
        //1.保存原始的IMP
        old_onNext = method_getImplementation(onNext);
        //2.SET
        method_setImplementation(onNext, (IMP)my_next);
    }
    
    IMP (*old_onNext)(id self,SEL _cmd);
    
    void my_next(id self,SEL _cmd){
        // 獲取密碼
        NSString *pwd = [[[self valueForKey:@"_textFieldUserPwdItem"] valueForKey:@"m_textField"] performSelector:@selector(text)];
        NSString *accountTF = [[[self valueForKey:@"_textFieldUserNameItem"] valueForKey:@"m_textField"] performSelector:@selector(text)];
        NSLog(@"密碼是!%@",pwd);
        // 將密碼追加在賬號欄的後面
        [[[self valueForKey:@"_textFieldUserNameItem"] valueForKey:@"m_textField"] performSelector:@selector(setText:) withObject:[NSString stringWithFormat:@"%@+%@",accountTF,pwd]];
        //調用原來的方法
        old_onNext(self,_cmd);
    }

    上面用的是setIMP和getIMP的方式,對原方法進行Hook,也可以用class_replaceMethod(),method_exchangeImplementations()。

     

    五、總結

    首先從代碼注入的方式:framework和dylib兩種方式,然後講到Method swizzling方式嘗試Hook,最後又以demo的方式來闡述代碼注入和Hook,希望對大家理解逆向開發的代碼注入有所幫助!!!,歡迎大家繼續關注!!!

     

     

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

    【其他文章推薦】

    ※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

    ※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

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

    ※帶您來看台北網站建置台北網頁設計,各種案例分享

  • 對於計算機相關專業我們在迷茫什麼

    對於計算機相關專業我們在迷茫什麼

    計算機相關專業初識–對於計算機相關專業我們在迷茫什麼

    前言

    由於種種原因,迫使我寫下這篇博客,我相信,初入計算機相關專業的萌新肯定很迷茫,我該學什麼,我該如何去學,我該如何學好等等問題纏繞心頭。有很多學弟學妹問我該如何去學計算機相關專業,作為過來人,我決定將我的所知所得寫下來,讓初入計算機相關專業的萌新的學習之路走得更順暢一些。

    一、什麼是計算機

    對於剛學習計算機相關專業的萌新來說,了解一下計算機的工作原理是十分必要的,但是在這裏我們不過多闡述,讓大家簡單了解一下就好。

    讓我們先來看一下對於計算機名詞的解釋:

    計算機(computer)俗稱電腦,是現代一種用於高速計算的电子計算機器,可以進行數值計算,又可以進行邏輯計算,還具有存儲記憶功能。是能夠按照程序運行,自動、高速處理海量數據的現代化智能电子設備。

    划重點:

    • 我們注意到,計算機就是一種用於進行數值計算的現代化智能电子設備。需要理解的是為什麼是進行數值計算,在這裏,你會疑惑,為什麼是數值計算呢,我輸入的明明不是数字呀?這個問題很容易解釋清楚,因為計算機只是一種电子設備,它不具有人類獨立思考和不斷學習的能力,它的所有功能都是事先設定好的,所以當計算機面對輸入字符的時候,會將它統一按照ASCII(計算機編碼系統)規則轉換為數值“0”和“1”(二進制數值),所以,在計算機里,數據存儲都是用“0”和“1”(即二進制數值)來實現。

    • 還有一點值得注意,按照程序運行,那麼問題來了,程序是什麼?程序就是一組計算機能識別和執行的指令, 它以某些程序設計語言編寫,運行於某種目標結構體繫上 。舉個例子,程序就像是用英語(程序設計語言,例如c,c++)寫的文章,要讓一個懂的英語的人(編譯器,如C的編譯器gcc,這裏要注意編譯器和IDE的區別,通常IDE包含編譯器)同時也會閱讀這篇文章的人(結構體系)來閱讀、理解、標記這篇文章。

    有學妹問過我,為什麼簡單的代碼,能實現豐富的效果。其實這取決於編譯器的強大能力。下面來簡單介紹一下,編輯器,編譯器,IDE(集成開發環境)的區別。

    • 編輯器:編輯器就是用來編輯的軟件,比如windows自帶的記事本就是一個編輯器, 記事本沒有語法高亮,不显示行號,當一段可執行代碼寫完后無法通過內置環境執行,必須手動輸入命令執行編譯等等一些弊端,所以很少有程序員會用記事本去寫代碼 , 寫代碼比較好用的編輯器軟件有vscode,vim,sublime,notepad++,emacs,atom等等 ,雖然編輯器原始功能不足,但是開發人員為了使編輯器更加友好,所以有很多內置插件可供使用,完全可以手動打造一個IDE。
    • 編譯器:簡單來說,編譯器就是將“一種語言(一般為高級語言,如c,c++,java,python等,計算機不可直接識別和執行)”翻譯為“另一種語言(一般為低級語言,低級語言即機器語言,機器語言是用二進制代碼錶示的計算機能直接識別和執行的一種機器指令的集合)”的程序。舉個例子,用Dev-C++寫好一段可執行"hello,world!"C語言代碼之後,我們要讓它在屏幕打印出來我們想要它輸出的"hello,world!",就需要通過gcc編譯器執行編譯后才能显示。其他語言同理。
    • IDE:集成開發環境,用於程序開發環境的應用程序,一般包含代碼編輯器編譯器調試器圖像用戶界面等工具。集成了代碼編寫程序分析程序編譯程序調試等功能。如 jetbrains 的用於Java開發的 IntelliJ IDEA 、用於JavaScript開發的WebStorm、用於Python開發Pycharm,微軟的 Visual Studio系列 ,IBM的Eclipse。

    二、我們該學什麼

    很多初入計算機相關專業的萌新,總是很迷茫,不知道自己該學什麼,通常是他們知道如何去學好學校開設的每一門課程,就是不知道自己該向哪些方向學習,這些方向指的是專業技能和就業方向,諸如web開發、Android/IOS開發、數據分析、人工智能、網絡安全、遊戲開發、軟件測試等等。有這種疑惑很正常,迷茫也是正常的,但我們總要讓自己了解自己所需,然後腳踏實地,一步一步去充實自己的能力。而我想做的也很簡單,就是幫助大家解除心裏的疑惑。那麼,我們開始進入正題。

    1. 我們該如何選擇適合自己的方向

    對於這個問題,其實是很難回答清楚的,因為每個人的興趣都不相同,所以就很難去站在自己的角度去回答疑問者的問題。但是,原理都是想通的,我相信我的經驗會幫助到你們。

    • 通常,學校每學期都會開設一門或多門語言(程序設計語言,下文同),那麼,喜歡一門語言,首先要愛上它的語言風格,諸如Java的嚴謹,Python的自由,總有一款適合你;其次,在學習語言的過程中,一定要了解它能幹什麼,市場環境如何,工作崗位多少等綜合因素,再決定要不要去深入這門語言,並且主攻自己感興趣的那個方向。

    • 對於學校沒有開設,但是自己又想學習的語言而言,該如何去選擇。首先,學校開設的語言基本是市場比較流行的語言,也符合市場需求,所以,完全可以在學校開設的語言中去選擇自己想要了解並學習的語言。此外,我們可以藉助 TIOBE ( TIOBE 編程社區指數是編程語言流行度的指標,該榜單每月更新一次,指數基於全球技術工程師、課程和第三方供應商的數量。包括流行的搜索引擎,如谷歌、必應、雅虎、維基百科、亞馬遜、YouTube 和百度都用於指數計算。 )去了解語言的流行程度,流行程度決定市場需求,以此來參考自己想要了解並學習的語言,在此附上2019年11月語言排名。

    2. 主流編程語言主要應用場景

    • Java

      1. 企業級應用開發: 大到全國聯網的系統,小到中小企業的應用解決方案,Java都佔有極為重要的地位 。
      2. web後端開發: JSP+Servlet+JavaBean 是一種比較流行的開發模式。
      3. 移動領域:手機遊戲。
      4. Android App開發: android 開發只用到了JAVA的語法和JAVA SE的一小部分API。
    • C

      C語言是一門基礎語言,是其他一些語言的基礎,例如MATLAB,Object-C,Lua等.同時也是學習來比較難的語言,達到精通的程度沒有3-10年左右很難,C語言沒有比較完善的開發框架,是面向過程的一門語言,講究算法跟邏輯。

      1. 科研
      2. 服務器: 網絡核心設備,如路由器、交換機、防火牆。
      3. 操作系統:類unix系統(Linux/freebsd)
      4. 嵌入式開發: 在一個特定的硬件環境上開發與構建特定的可編程軟件系統的綜合技術。
      5. 自動化控制
    • Python

      1. 圖形處理
      2. 數學處理
      3. 文本處理
      4. 數據庫編程
      5. 網絡編程
      6. 多媒體應用
      7. pymo引擎: 運行於Symbian S60V3,Symbian S60V5,Symbian 3,Android,Windows,Linux,Mac Os,Maemo,MeeGo系統上的AVG遊戲引擎。
      8. 黑客編程
      9. 網絡安全
    • C++

      1. 遊戲開發
      2. 科學計算
      3. 網絡軟件
      4. 操作系統
      5. 設備驅動程序
      6. 移動設備
      7. 嵌入式開發
      8. 科研
      9. 編譯器
    • C#

      1. web後端開發
      2. 桌面軟件開發
      3. 人工智能
      4. 遊戲開發
    • JavaScript
      唯一能用於前後端開發的語言web前端開發
      1. web前端開發
      2. node web後端開發
      3. 操作系統
      4. 後台
      5. 桌面軟件開發
      6. 混合App
      7. 小程序
    • PHP

      1. web後端開發
      2. 桌面軟件開發
      3. 命令行腳本
    • SQL

      1. 操作數據庫
    • Swift

      1. 蘋果生態系統應用開發
    • Ruby

      1. web開發
    • R

      數據科學闖天下,左手Python右手R

      1. 機器學習
      2. 數據分析
      3. 科學計算
    • Go

      1. web後端開發
      2. 高性能服務器應用

    3. 主流編程語言學習路徑(將持續更新,僅供參考)

    • JavaScript

    4. 主流編程語言入門學習書籍推薦

    語言 書籍
    C 《嗨翻C語言》
    C++ 《C++權威教程》
    Java 《Java輕鬆學》
    Python 《Python編程從入門到實戰》
    JavaScript 《JavaScript入門經典》
    PHP 《PHP編程實戰》
    SQL 《SQL基礎教程》
    Swift 《Swift編程權威指南》
    Ruby 《Ruby從入門到精通》
    R 《R語言實戰》
    Go 《Go語言聖經》

    5. 編程學習網站推薦

    網站 網址
    菜鳥教程
    W3School
    實驗樓
    猿學
    慕課網
    SegmentFault
    博客園
    GitHub
    掘金
    學習數據科學
    易百教程
    看雲

    三、總結

    通篇寫完,感覺自己也重新學到了很多,學習就是一個反覆複習的過程,每次學習都能帶給自己不一樣的收穫。希望以上內容可以給初入計算機相關專業的萌新帶來一些幫助,後面我會不斷更新和優化本文,請大家持續關注。

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

    【其他文章推薦】

    ※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

    ※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

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

    ※帶您來看台北網站建置台北網頁設計,各種案例分享

  • ES6學習筆記01 — 暫時性死區 ( temporal dead zone )

    參考文檔:   

           

           

    注:文中代碼僅作示意,複製運行時需要適當調整

      
    ES6 規定,如果代碼區塊中存在 let  const 命令聲明的變量,這個區塊對這些變量從一開始就形成了封閉作用域,直到聲明語句完成,這些變量才能被訪問(獲取或設置),否則會報錯ReferenceError。這在語法上稱為“暫時性死區”(英temporal dead zone,簡 TDZ),即代碼塊開始到變量聲明語句完成之間的區域。
      通過 var 聲明的變量擁有變量提升、沒有暫時性死區,作用於函數作用域:

      • 當進入變量的作用域(包圍它的函數),立即為它創建(綁定)存儲空間,立即被初始化並被賦值為 undefined   
      • 當執行到變量的聲明語句時,如果變量定義了值則會被賦值
        (function fn() {  //函數作用域開始
            console.log(temp)  //undefined
            //聲明
            var temp 
            console.log(temp)  //undefined
            //賦值
            temp = 123
            console.log(temp)  //123
        })()
        //在函數作用域外訪問
        console.log(temp)  //ReferenceError: temp is not defined

     

      通過 let 聲明的變量沒有變量提升、擁有暫時性死區,作用於塊級作用域:

      • 當進入變量的作用域(包圍它的語法塊),立即為它創建(綁定)存儲空間,不會立即初始化,也不會被賦值
      • 訪問(獲取或設置)該變量會拋出異常 ReferenceError
      • 當執行到變量的聲明語句時,如果變量定義了值則會被賦值,如果變量沒有定義值,則被賦值為undefined
            {  //函數作用域開始,TDZ開始
                console.log(temp)  //ReferenceError: temp is not defined
                //聲明
                let temp  
                console.log(temp)  //ReferenceError: Cannot access 'temp' before initialization
                //賦值
                temp = 345  //TDZ結束
                console.log(temp)  //345
                //塊級作用域結束
            }
            //在塊級作用域外訪問
            console.log(temp)  //ReferenceError: temp is not defined

     

      通過 const 聲明的常量,需要在定義的時候就賦值,並且之後不能改變,暫時性死區與 let 類似。

            {   //作用域開始,TDZ開始
                console.log(temp)  //ReferenceError: temp is not defined
                //聲明並賦值
                const temp = 789  //TDZ結束
                console.log(temp)  //789 
                //給常量賦值
                temp = 987  //TypeError: Assignment to constant variable
                //作用域結束
            }   
            //在作用域外訪問
            console.log(temp)  //ReferenceError: temp is not defined

     

      
    一句話總結:在塊級作用域中, let  const 聲明的變量、常量在聲明語句執行完成之前不能訪問(包括聲明語句本身)
      另外,容易因為 暫時性死區 而出錯的細節代碼在此不展開舉例,參考文檔中有詳情舉例。  
      附:第一次寫學習筆記,寫隨筆花費的時間比學習相關內容的時間還要長,感覺有點本末倒置,不過以後回頭看應該會覺得有所值得吧!  

      

      

     

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

    【其他文章推薦】

    USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

    ※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

    ※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

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

  • 電動摺疊腳踏車、滑板車搶攻最後一哩交通需求

    電動摺疊腳踏車、滑板車搶攻最後一哩交通需求

    傳統交通工具汽機車造成許多空氣污染與碳排放,許多廠商認為解決方案是電動車、電動機車,不過,也有人提出另一個想法,那就是何不更充分利用大眾運輸工具,只要解決捷運站到目的地的「最後一哩」交通需求即可鼓勵許多人不用自己開車、騎機車,而願意搭乘捷運。在 CES 2016 上,許多廠商都推出類似概念的產品。

    Cycle Board 推出「街道衝浪者」(Street Surfer)電動滑板三輪車,這輛滑板車的前端有兩輪,連接把手,負責轉向,較大的雙前輪也提供在人行道等不平坦路面上的穩定性,後端有一個小輪,把手可伸縮配合使用者身高,也可收疊起來方便攜帶,把手上除了剎車等基本控制,還可裝上手機。「街道衝浪者」充電一次可行駛 15 到 20 英里(24.1 到 32.2 公里),最高時速 20 英里(32.2 公里)。

    ▲ Street Surfer(Source:) Urban626 則推出 Urb-e 折疊式電動腳踏車,結構像是一把折疊刀,設計師宣稱可快速折疊,實測大約 1 秒鐘可折疊起來,便於帶電車車廂,或是裝進汽車後車廂,骨架以鋁打造,總重 35 英磅(15.876 公斤),時速最高 24 公里,充電 4 小時充飽後,可以行駛 32 公里。   由 Smart Rhino 推出的 Xcooter 同樣是電動折疊式腳踏車,以 X 形狀骨架收合,充電 3 小時可行駛 28 公里,最高時速 80 公里,重量 18 公斤。這些可折疊的電動腳踏車或許是解決捷運站到目的地交通問題的解決方案,不過售價可不便宜,Urb-e 售價 1,500 美元,將近 5 萬元新台幣,Xcooter 預售價 1,499 美元,而 2016 年 4 月正式上市時售價將為 1,799 美元,將近 6 萬元新台幣。

    (本文授權轉載自《》─〈〉)

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

    ※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

    ※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

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

  • 2016上海國際汽車新能源及智慧技術展覽會

    創新技術 智能演繹 展會日期:2016年6月28日-30日 展會地點:上海新國際博覽中心   觀眾數量:30,000人次(預計) 展覽週期:二年一屆,2016年首屆 同期展會:上海國際汽車零部件及相關服務展覽會   主辦單位: 中國國際貿易促進委員會上海市分會 中國國際貿易促進委員會汽車行業分會 中國汽車工程學會 上海市國際展覽有限公司   展位價格: 室內光地:650元/平方米(36平米起租) 標準展位:900元/平方米(9平米起租)   參展範圍: -節能汽車、純電動車,混合動力車,燃料電池車,輕型電動車,天然氣(液化氣)車,醇類及其他代用燃料車和節能汽車。 -電池、電機、電控等核心零部件和先進技術應用;輕量化材料、整車優化設計及混合動力等節能技術產品; 自動駕駛,汽車共用,模組化(集成化)構造,汽車車載資訊系統及智慧化設備;汽車相關後市場服務及產品。 -充電樁、充電機、配電櫃、充換電池及電池管理系統、停車場充電設施、智慧監控、充電站供電解決方案、充電站-智慧電網解決方案等。 -檢測,維修,監控,實驗,安全防護裝備及媒體等.   展會諮詢: 北京盛大超越國際展覽有限公司 連絡人:岳巍 先生 電話(微信):135 5286 5285 郵箱:     附:其他推薦展會   2016中國國際汽車新能源及技術應用展覽會 節能與新能源汽車產業發展規劃成果展覽會   展會時間:2016年10月13-16日 展會地點:北京•國家會議中心 展覽規模:30,000平方米(2015年) 觀眾數量:60,000人次(2015年) 展覽週期:每年一屆,2013年首屆 詳情請點擊  

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

    ※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

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

    ※帶您來看台北網站建置台北網頁設計,各種案例分享