1. 程式人生 > >1、為什麼程式設計中建議使用netty而不是用jdk nio?

1、為什麼程式設計中建議使用netty而不是用jdk nio?

如果對nio瞭解比較透徹的話,就不會糾結這個問題了,畢竟市面上流行的中介軟體,如mycat ,spark都是用的nio,當然使用netty的更多,如dubbo;

我們需要知道nio的原理,同時也不必亂造輪子。

使用jdk-nio你需要掌握linux-selector原理,就是將所有的channel註冊到一個selector上,selector通過輪詢檢測,判斷這些channel是否是可用的,如 可讀,可寫,已連線等。如果是可用的需要進一步處理,不能用當前執行緒進行處理,這樣會造成執行緒阻塞,應該使用執行緒池來處理。

需要熟悉jdk-nio提供的幾個關鍵類:Selector , SocketChannel , ServerSocketChannel , FileChannel ,ByteBuffer ,SelectionKey 。完成一次呼叫需要用到這些物件。

需要知道網路知識:
tcp粘包,半包
網路閃斷
網路阻塞
包體溢位
包體重複傳送

需要知道linux底層實現,如selector ,如何正確的關閉channel,如何退出登出selector ,如何避免selector太過於頻繁。

需要知道如何讓client端獲得server端的返回值,然後才返回給前端,需要如何等待或在怎樣作熔斷機制。

需要知道物件序列化,及序列化演算法。

TCP 滑動窗體技術

在tcp學習中,我們知道有個技術叫滑動窗體技術,就是接收端會向傳送端傳送一條訊息,下次可以接受多少長度的內容,以免接收方不能接收過多的資料。

滑動視窗(Sliding Window)

TCP/UDP以及其他協議都可以完成資料的傳輸,從一端傳輸到另外一端,TCP比較出眾的一點就是提供一個可靠的,流控的資料傳輸,所以實現起來要比其他協議複雜的多,先來看下這兩個修飾詞的意義:

  1. Reliability ,提供TCP的可靠性,TCP的傳輸要保證資料能夠準確到達目的地,如果不能,需要能檢測出來並且重新發送資料。

  2. Data Flow Control,提供TCP的流控特性,管理髮送資料的速率,不要超過裝置的承載能力

為了能夠實現以上2點,TCP實現了很多細節的功能來保證資料傳輸,比如說 滑動視窗適應系統,超時重傳機制,累計ACK等。

IP層協議屬於不可靠的協議,IP層並不關係資料是否傳送到了對端,TCP通過確認機制來保證資料傳輸的可靠性,在比較早的時候使用的是send–wait–send的模式,其實這種模式叫做stop-wait模式,傳送資料方在傳送資料之後會啟動定時器,但是如果資料或者ACK丟失,那麼定時器到期之後,收不到ACK就認為傳送出現狀況,要進行重傳。這樣就會降低了通訊的效率,如下圖所示,這種方式被稱為 positive acknowledgment with retransmission (PAR):

可以假設一下,來優化一下PAR效率低的缺點,比如我讓傳送的每一個包都有一個id,接收端必須對每一個包進行確認,這樣裝置A一次多傳送幾個片段,而不必等候ACK,同時接收端也要告知它能夠收多少,這樣傳送端發起來也有個限制,當然還需要保證順序性,不要亂序,對於亂序的狀況,我們可以允許等待一定情況下的亂序,比如說先快取提前到的資料,然後去等待需要的資料,如果一定時間沒來就DROP掉,來保證順序性!

在TCP/IP協議棧中,滑動視窗的引入可以解決此問題,先來看從概念上資料分為哪些類

  1. Sent and Acknowledged:這些資料表示已經發送成功並已經被確認的資料
    28~31中的bytes,這些資料其實的位置是在視窗之外,因為視窗內順序最低的被確認之後,要移除視窗,實際上是視窗進行合攏,同時開啟接收新的帶傳送的資料

  2. Send But Not Yet Acknowledged:這部分資料稱為傳送但沒有被確認,資料被髮送出去,沒有收到接收端的ACK,認為並沒有完成傳送,這個屬於視窗內的資料。

  3. Not Sent,Recipient Ready to Receive:這部分是儘快傳送的資料,這部分資料已經被載入到快取中,也就是視窗中了,等待發送,其實這個視窗是完全有接收方告知的,接收方告知還是能夠接受這些包,所以傳送方需要儘快的傳送這些包

  4. Not Sent,Recipient Not Ready to Receive: 這些資料屬於未傳送,同時接收端也不允許傳送的,因為這些資料已經超出了傳送端所接收的範圍

接收端也是有一個接收視窗的,類似傳送端,接收端的資料有3個分類,因為接收端並不需要等待ACK所以它沒有類似的接收並確認了的分類,情況如下

  1. Received and ACK Not Send to Process:這部分資料屬於接收了資料但是還沒有被上層的應用程式接收,也是被快取在視窗內

  2. Received Not ACK: 已經接收並,但是還沒有回覆ACK,這些包可能輸屬於Delay ACK的範疇了

  3. Not Received:有空位,還沒有被接收的資料。

對於傳送方來講,視窗內的包括兩部分,就是傳送視窗(已經發送了,但是沒有收到ACK);可用視窗,接收端允許傳送但是沒有傳送的那部分稱為可用視窗。

  1. Send Window : 20個bytes 這部分值是有接收方在三次握手的時候進行通告的,同時在接收過程中也不斷的通告可以傳送的視窗大小,來進行適應

  2. Window Already Sent: 已經發送的資料,但是並沒有收到ACK。

滑動視窗原理

TCP並不是每一個報文段都會回覆ACK的,可能會對兩個報文段傳送一個ACK,也可能會對多個報文段傳送1個ACK【累計ACK】,比如說傳送方有1/2/3 3個報文段,先發送了2,3 兩個報文段,但是接收方期望收到1報文段,這個時候2,3報文段就只能放在快取中等待報文1的空洞被填上,如果報文1,一直不來,報文2/3也將被丟棄,如果報文1來了,那麼會發送一個ACK對這3個報文進行一次確認。

舉一個例子來說明一下滑動視窗的原理:

  1. 假設32~45 這些資料,是上層Application傳送給TCP的,TCP將其分成四個Segment來發往internet

  2. seg1 32~34 seg3 35~36 seg3 37~41 seg4 42~45 這四個片段,依次傳送出去,此時假設接收端之接收到了seg1 seg2 seg4

  3. 此時接收端的行為是回覆一個ACK包說明已經接收到了32~36的資料,並將seg4進行快取(保證順序,產生一個儲存seg3 的hole)

  4. 傳送端收到ACK之後,就會將32~36的資料包從傳送並沒有確認切到傳送已經確認,提出視窗,這個時候視窗向右移動

  5. 假設接收端通告的Window Size仍然不變,此時視窗右移,產生一些新的空位,這些是接收端允許傳送的範疇

  6. 對於丟失的seg3,如果超過一定時間,TCP就會重新傳送(重傳機制),重傳成功會seg3 seg4一塊被確認,不成功,seg4也將被丟棄

不斷重複著上述的過程,隨著視窗不斷滑動,將真個資料流傳送到接收端,實際上接收端的Window Size通告也是會變化的,接收端根據這個值來確定何時及傳送多少資料,從對資料流進行流控。原理圖如下圖所示:

滑動視窗動態調整
主要是根據接收端的接收情況,動態去調整Window Size,然後來控制傳送端的資料流量

客戶端不斷快速傳送資料,伺服器接收相對較慢,看下實驗的結果

a. 包175,傳送ACK攜帶WIN = 384,告知客戶端,現在只能接收384個位元組

b. 包176,客戶端果真只發送了384個位元組,Wireshark也比較智慧,也宣告TCP Window Full

c. 包177,伺服器回覆一個ACK,並通告視窗為0,說明接收方已經收到所有資料,並儲存到緩衝區,但是這個時候應用程式並沒有接收這些資料,導致緩衝區沒有更多的空間,故通告視窗為0, 這也就是所謂的零視窗,零視窗期間,傳送方停止傳送資料

d. 客戶端察覺到視窗為0,則不再發送資料給接收方

e. 包178,接收方傳送一個視窗通告,告知傳送方已經有接收資料的能力了,可以傳送資料包了

f. 包179,收到視窗通告之後,就傳送緩衝區內的資料了.

總結一點,就是接收端可以根據自己的狀況通告視窗大小,從而控制傳送端的接收,進行流量控制。

TCP為什麼會發生粘包問題呢?

其實就是滑動窗體的大小決定的,如果可用窗體較大,那就可以裝下多個tcp請求的資訊(粘包);如果可用窗體較小,就有可能發生對一個tcp的請求資訊進行拆包。

由於tcp不能理解應用層(http/..)的業務資料,所以tcp無法保證資料不被拆包或粘包。這隻能由業務層對其解決。
常見的解決方法:
1、業務資料定長,不足用空格填充,缺點是業務資料比設定的資料更長。
2、特定字元分割,如回車健。
3、對業務資料長度進行統計,放在訊息體的前4位byte中;這是通用做法。
這些都是通過應用層的處理方法,有沒有在傳輸控制層的解決方法呢?解決方法就是模擬應用層傳送和接收訊息,來解決tcp的粘包問題。

模擬粘包

讓client迴圈向server傳送訊息,業務資料因小於可用包體,發生粘包。

LineBasedFrameDecoder如何解決粘包?

其實就是運用了前面所說的第二種方法,對特定字元(\r\n,\n)進行拆分處理;
但不能處理拆包問題,因為最後一行沒有出現(\r\n,\n)就到達可用包體尾部。
如果最後一行沒有出現(\r\n,\n),LineBasedFrameDecoder會丟擲異常。
LineBasedFrameDecoder 一般和StringDecoder配合使用,LineBasedFrameDecoder負責對拆分,StringDecoder把一行資料轉換為字串,方便後面使用,也可不用StringDecoder,使用ByteBuf物件。

自定義分隔符

在netty包io.netty.handler.codec中,定義了許多**Decoder,其中DelimiterBasedFrameDecoder就是提供自定義分割符的Decoder,使用如下:

public void initChannel(SocketChannel ch) throws Exception {
    ByteBuf delimiter = Unpooled.copiedBuffer("$_" .getBytes());
    ch.pipeline()
         .addLast( new DelimiterBasedFrameDecoder(1024,delimiter));
         //1024 如果達到1024byte還沒有找到風格符,丟擲異常。
    ch.pipeline().addLast(new StringDecoder());
    ch.pipeline().addLast(new EchoServerHandler());
}

為什麼不需要處理拆包或半包問題?

拆包或半包是由於滑動窗體的長度不夠裝下完整的業務資料,但是在下一次接收的時候會保證之後的業務資料,直到所有的業務資料被接收完成,所以無需作特別的處理。

FixedLengthFrameDecoder定長解碼

如下使用:

channel.pipeline().addLast(new FixedLengthFrameDecoder(10));

缺點是如果業務資料比定長還長,解碼會有問題。

LengthFieldBasedFrameDecoder

大多數的協議(私有或者公有),協議頭中會攜帶長度欄位,用於標識訊息體或者整包訊息的長度,例如SMPP、HTTP協議等。由於基於長度解碼需求的通用性,Netty提供了LengthFieldBasedFrameDecoder,自動遮蔽TCP底層的拆包和粘 包問題,只需要傳入正確的引數,即可輕鬆解決“讀半包“問題。

public LengthFieldBasedFrameDecoder
    (ByteOrder byteOrder, int maxFrameLength, int lengthFieldOffset, 
    int lengthFieldLength, int lengthAdjustment,  int initialBytesToStrip, 
    boolean failFast) {
        ...
}

byteOrder:表示位元組流表示的資料是大端還是小端,用於長度域的讀取;預設是“BIG_ENDIAN” ,//LITTLE_ENDIAN

maxFrameLength:表示的是包的最大長度,超出包的最大長度netty將會做一些特殊處理;

lengthFieldOffset:指的是長度域的偏移量,表示跳過指定長度個位元組之後的才是業務資料長度域;如果有header的話需要做考慮。

lengthFieldLength:用來記錄該幀資料長度的欄位本身的長度;

.addLast(new LengthFieldBasedFrameDecoder(65536, 0, 4, 0, 0))

lengthAdjustment:該欄位加長度欄位等於資料幀的長度,包體長度調整的大小,長度域的數值表示的長度加上這個修正值表示的就是帶header的包;

initialBytesToStrip:從資料幀中跳過的位元組數,表示獲取完一個完整的資料包之後,忽略前面的指定的位數個位元組,應用解碼器拿到的就是不帶長度域的資料包;

failFast:如果為true,則表示讀取到長度域,TA的值的超過maxFrameLength,就丟擲一個 TooLongFrameException,而為false表示只有當真正讀取完長度域的值表示的位元組之後,才會丟擲 TooLongFrameException,預設情況下設定為true,建議不要修改,否則可能會造成記憶體溢位。

LengthFieldBasedFrameDecoder定義了一個長度的欄位來表示訊息的長度,因此能夠處理可變長度的訊息。將訊息分為訊息頭和訊息體,訊息頭固定位置增加一個表示長度的欄位,通過長度欄位來獲取整包的資訊。LengthFieldBasedFrameDecoder繼承了ByteToMessageDecoder,即轉換位元組這樣的工作是由ByteToMessageDecoder來完成,而LengthFieldBasedFrameDecoder只用安心完成他的解碼工作就好。Netty在解耦和方面確實做的不錯。

物件為什麼要序列化?

從java中的物件深複製中,得到了啟示,將一個持久化物件轉換為一個記憶體物件。
如果不序列化,就不能恢復物件了麼?其實不是,持久化物件的實質是一個二進位制陣列。序列化只是程式上作為標示,表明這個物件在序列化和反序列化還需要做一些什麼樣的補充。

java序列化的缺點:
1、壓縮耗費時間長
2、壓縮後陣列較大

使用陣列+物件流可以知道jdk序列化後的陣列大小。
序列化過程的實質是物件變為流的過程。

我們通常以為將Java物件序列化成二進位制比序列化成XML或Json更快,其實是錯誤的,如果你關心效能,建議避免Java序列化。

Java序列化有很多的要求,最主要的一個是包含能夠序列化任何東西(或至少任何實現Serializable介面)。這樣才能進入其他JVM之中,這很重要,所以有時效能不是主要的要求,標準的格式才最重要。
Ordr程式碼:

public class Order implements Serializable {
private long id;
private String description;
private BigDecimal totalCost = BigDecimal.valueOf(0);
private List orderLines = new ArrayList();
private Customer customer;

我們經常看到CPU花費很多時間內進行Java序列化,下面我們研究一下,假設一定Order,雖然只有幾個位元組,但是序列化以後不是幾十個位元組,而是600多個位元組:
序列化輸出:

—-sr–model.Order—-h#—–J–idL–customert–Lmodel/Customer;L–descriptiont–Ljava/lang/String;L–orderLinest–Ljava/util/List;L–totalCostt–Ljava/math/BigDecimal;xp——–ppsr–java.util.ArrayListx—–a—-I–sizexp—-w—–sr–model.OrderLine–&-1-S—-I–lineNumberL–costq-~–L–descriptionq-~–L–ordert–Lmodel/Order;xp—-sr–java.math.BigDecimalT–W–(O—I–scaleL–intValt–Ljava/math/BigInteger;xr–java.lang.Number———–xp—-sr–java.math.BigInteger—–;—–I–bitCountI–bitLengthI–firstNonzeroByteNumI–lowestSetBitI–signum[–magnitudet–[Bxq-~———————-ur–[B——T—-xp—-xxpq-~–xq-~–

正如你可能已經注意到,Java序列化寫入不僅是完整的類名,也包含整個類的定義,包含所有被引用的類。類定義可以是相當大的,也許構成了效能和效率的問題,當然這是編寫一個單一的物件。如果您正在編寫了大量相同的類的物件,這時類定義的開銷通常不是一個大問題。另一件事情是,如果你的物件有一類的引用(如元資料物件),那麼Java序列化將寫入整個類的定義,不只是類的名稱,因此,使用Java序列化寫出元資料(meta-data)是非常昂貴的。

Externalizable
通過實現Externalizable介面,這是可能優化Java序列化的。實現此介面,避免寫出整個類定義,只是類名被寫入。它需要你實施readExternal和writeExternal方法方法的,所以需要做一些工作,但相比僅僅是實現Serializable更快,更高效。

Externalizable對小數目物件有效的多。但是對大量物件,或者重複物件,則效率低,必須重寫readExternal和writeExternal方法來知道那些屬性是需要被記錄的。
序列化輸出:

—-sr–model.Order—*3–^—xpw———psr–java.math.BigDecimalT–W–(O—I–scaleL–intValt–Ljava/math/BigInteger;xr–java.lang.Number———–xp—-sr–java.math.BigInteger—–;—–I–bitCountI–bitLengthI–firstNonzeroByteNumI–lowestSetBitI–signum[–magnitudet–[Bxq-~———————-ur–[B——T—-xp—-xxpsr–java.util.ArrayListx—–a—-I–sizexp—-w—–sr–model.OrderLine-!!|—S—xpw—–pq-~–q-~–xxx
參考:https://blog.csdn.net/caomiao2006/article/details/51588927

序列化成XML或JSON可以允許其他語言訪問,可以實現REST服務等。缺點是文字格式的效率比優化的二進位制格式低一些。

Kryo
Kryo 是一種快速,高效的序列化的Java框架。 KRYO是新的BSD許可下一個開源專案提供。這是一個很小的專案,只有3名成員,它首先在2009年出品。

工作原理類似於Java序列化KRYO,尊重瞬態欄位,但不要求一類是可序列化的。KRYO有一定的侷限性,比如需要有一個預設的建構函式的類,在序列化將java.sql.Time java.sql.Date java.sql.Timestamp類會遇到一些問題。

order序列化結果:

——java-util-ArrayLis—–model-OrderLin—-java-math-BigDecima———model-Orde—–

相關推薦

1為什麼程式設計建議使用netty不是用jdk nio?

如果對nio瞭解比較透徹的話,就不會糾結這個問題了,畢竟市面上流行的中介軟體,如mycat ,spark都是用的nio,當然使用netty的更多,如dubbo; 我們需要知道nio的原理,同時也不必亂造輪子。 使用jdk-nio你需要掌握linux-sele

1java自己覺得重要的部分——未完待續

一、JAVA基礎語言: 1、集合/容器部分: 1、Collection 增加、遍歷、刪除: public interface Collection<E> extends Iterable<E>  2、List: public interface

1cmd輸入 java -version 時出現錯誤,如下:

1、cmd中輸入 java -version 時出現錯誤,如下: Error: could not find java.dll       Eclipse:Error:could not find java SE Runtime Environment  

1DB的null在js的顯示結果

undefine style lse pan 怎麽 name dem nbsp dir 記錄是為了更好的成長! 之前一直沒弄明白DB中是null的話在前臺怎麽判斷,到底是null還是undefined?做demo測試結果如下: DB: name = nullJ

【Java網路程式設計】:Netty實現OIO和NIO

承接上文:https://blog.csdn.net/hxcaifly/article/details/85274664 前言 單純地使用Java JDK來實現網路NIO是一件開發成本非常高的事情。然而,Netty 為它所有的傳輸實現提供了一個通用API,這使得這種

ACMNO.11 一個數如果恰好等於它的因子之和,這個數就稱為"完數"。 例如,6的因子為123,6=1+2+3,因此6是"完數"。 程式設計序找出N之內的所有完數,並按下面格式輸出其因子

寫在前面,心得感悟~ 程式碼越來越有難度! 這個ACM題,我除錯了 將近50次~ 一個小時! 真的是,年紀輕輕的搞什麼ACM呀! 關於題的解決思路放在下面再寫吧! 題目描述 一個數如果恰好等於它的因子之和,這個數就稱為"完數"。 例如,6的因子為1、2、3,而6=1+2+

iOS開發之網路程式設計--1AFNetwork 3.x 的所有開發常用基礎介紹

前言:第三方網路請求框架中AFNetwork 3.x收歡迎程度相當高的: 由於iOS 7 和 Mac OS X 10.9 Mavericks 中一個顯著的變化就是對 Foundation URL 載入系統的徹底重構。而且現在AFN 3.x版本 完全摒棄了NSURLConnection,而使用了NSURL

關於面向物件程式設計很多人用get()和set()方法,不用public的一點總結

在很多程式中,都喜歡定義一個privata變數,然後為這個私有變數加上get(),set()方法。那為什麼不直接定義一個public變數呢?這樣做到底有什麼好處和意義呢?難道真的僅僅只是為了程式碼規範?別逗了,不管你信不信,反正我是不信!帶著這個問題我在網上尋找答案,真是眾

[TLSR8266] 1搭建tlsr8266編譯框架在win服務器

通過命令 bject 結束 str 令行 obj 環境 適合 問題 前言 泰淩微TLSR8266藍牙芯片的開發環境在win桌面系統中搭建起來比較簡單,在其論壇SDK版塊->Telink IDE中可以找到安裝包,直接安裝即可生成基於Eclipse的開發環境,及相

Oracle count(1) count(*) 和count(列名) 函數的區別

select sdn 快的 包含 varchar2 into 要去 tails lan 1)count(1)與count(*)比較: 1、如果你的數據表沒有主鍵,那麽count(1)比count(*)快2、如果有主鍵的話,那主鍵(聯合主鍵)作為count的條件也比count

SQL SERVER 下:1遞歸查詢父分類下的各個子分類。 2查詢每個商品分類最貴的前兩個商品SQL

nio span clas 適用於 商品 一行 class com 分享圖片 1、遞歸查詢父分類下的各個子分類。表設計: SQL: --CTE 語句(適用於MSSQL2005以後版本) with cte_testNavi(Id,Name,Pid ) as ( --這是查

[占坑] 圖像處理計算積分圖使用類似dp的方法不用樹狀數組的原因

處理 數組 樹狀 預處理 樹狀數組 方法 pos 二維 post   占個坑,目前知道的幾條原因: 1.dp的狀態轉義方程很簡單:f(i,j)=f(i-1,j)+f(i,j-1)-f(i-1,j-1)+rgb(i,j),預處理復雜度是O(nm),查詢的復雜度為O(1)。而使

1軟件源配置與學習建議

rem entos ping ont IT ans yun height line 默認使用centos6.8默認aliyun的源備份mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo

項目一:第十二天 1常見權限控制方式 2基於shiro提供url攔截方式驗證權限 3在realm授權 5總結驗證權限方式(四種) 6用戶註銷7基於treegrid實現菜單展示

eal 重復數 規則 認證通過 delete get 數據庫 filter 登陸 1 課程計劃 1、 常見權限控制方式 2、 基於shiro提供url攔截方式驗證權限 3、 在realm中授權 4、 基於shiro提供註解方式驗證權限 5、 總結驗證權限方式(四種) 6、

【劍指offer】431~n整數1出現的次數

ase 表示 eight pre pub 題目 我們 return 1出現的次數 題目 輸入一個整數,求1~n的整數十進制表示中1出現的次數。如12,有1,10,11,12,總共出現了5次。 思路 註意不是統計出現1的數字的多少,而是統計1出現了幾次。 我們按位來分析 個位

1二維數組的查找

維數 nbsp target 題目 turn 二維數組中的查找 www. rmi while 題目描述 在一個二維數組中(每個一維數組的長度相同),每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成一個函數,輸入這樣的一個二維數組和一個整數,判

【劍指offor】1二維陣列的查詢

題目連結: 二維陣列中的查詢 題目描述: 在一個二維陣列中(每個一維陣列的長度相同),每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成一個函式,輸入這樣的一個二維陣列和一個整數,判斷陣列中是否含有該整數。 解題思路 兩種思路 方法1

shell輸入輸出重定向,>>><<>/dev/null2>&1<<end<<EOF等

轉載自:https://www.jb51.net/article/106373.htm https://blog.csdn.net/qq_31073871/article/details/80810306 其他參考:www.runoob.com/linux/linux-shell-io-re

《愛麗絲夢遊仙境1》:在慌亂祕境為自我戰,何懼..

阿里巴巴官方釋出微博稱,連續幾日,一篇名為《阿里員工透露:馬總早移走 1200 億人民幣!網友:不愧是老師》的文章被有組織的進行惡意傳播。阿里巴巴官方釋出微博稱,連續幾日,一篇名為《阿里員工透露:馬總早移走 1200 億人民幣!網友:不愧是老師》的文章被有組織的進行惡意傳播。 對此,阿里表示,該文完全捏造事

常見位操作及運算應用舉例:1,C語言位運算子異或“∧”的作用2,異或運算的作用3,&(與運算)|(或運算)^(異或運算)

  1 C語言中位運算子異或“∧”的作用: 異或運算子∧也稱XOR運算子。它的規則是若參加運算的兩個二進位同號,則結果為0(假);異號則為1(真)。即0∧0=0,0∧1=1,1∧1=0。如: 即071∧052,結果為023(八進位制數)。 “異或”的意思是判斷兩個相應的位值是否為“