最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java ByteBuffer網(wǎng)絡(luò)編程用法實例解析

 更新時間:2020年10月21日 10:22:51   作者:cuisuqiang  
這篇文章主要介紹了Java ByteBuffer網(wǎng)絡(luò)編程用法實例解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下

做tcp網(wǎng)絡(luò)編程,要解析一批批的數(shù)據(jù),可是數(shù)據(jù)是通過Socket連接的InputStream一次次讀取的,讀取到的不是需要轉(zhuǎn)換的對象,而是要直接根據(jù)字節(jié)流和協(xié)議來生成自己的數(shù)據(jù)對象。

按照之前的編程思維,總是請求然后響應(yīng),當(dāng)然Socket也是請求和響應(yīng),不過與單純的請求響應(yīng)是不同的。

這里Socket連接往往是要保持住的,也就是長連接,然后設(shè)置一個緩沖區(qū),網(wǎng)絡(luò)流不斷的追加到緩沖區(qū)。然后后臺去解析緩沖區(qū)的字節(jié)流。

如圖所示,網(wǎng)絡(luò)的流一直在傳遞,我們收到也許是完成的數(shù)據(jù)流,也可能是沒有傳遞完的。這里就需要監(jiān)視管道,不斷讀取管道中的流數(shù)據(jù),然后向緩沖區(qū)追加。程序從頭開始解析,如果目前緩沖區(qū)包含了數(shù)據(jù),則解析,沒有則放棄繼續(xù)讀取管道流。

就算管道中包含了數(shù)據(jù),也不一定包含了完成的數(shù)據(jù)。例如,100個字節(jié)是一個數(shù)據(jù)體,可是目前緩沖區(qū)內(nèi)包含了120個字節(jié),這就是說緩沖區(qū)包含了一條數(shù)據(jù),但是還有沒有傳遞完的字節(jié)流。那么就要把前100個字節(jié)拿出來解析,然后從緩沖區(qū)清除這100個字節(jié)。那緩沖區(qū)就剩下20個字節(jié)了,這些數(shù)據(jù)可能在下次流中補充完成。

如何建立緩沖?

/** 
 * 全局MVB數(shù)據(jù)緩沖區(qū) 占用 1M 內(nèi)存 
 */ 
private static ByteBuffer bbuf = ByteBuffer.allocate(10240); 
 
/** 
 * 線程安全的取得緩沖變量 
 */ 
public static synchronized ByteBuffer getByteBuffer() { 
  return bbuf; 
} 

寫一個Socket客戶端,該客戶端得到Socket連接,然后讀取流,一直向緩沖中追加字節(jié)流,每次追加后調(diào)用一個方法來解析該流

public void run() { 
  Socket socket = GlobalClientKeep.mvbSocket; 
  if (null != socket) { 
    try { 
      // 獲得mvb連接引用 
      OutputStream ops = socket.getOutputStream(); 
      InputStream ips = socket.getInputStream(); 
      while (true) { 
        if (null != ops && null != ips) { 
          // 接收返回信息 
          byte[] bt = StreamTool.inputStreamToByte(ips); 
          ByteBuffer bbuf = GlobalCommonObjectKeep.getByteBuffer(); 
          // 設(shè)置到緩沖區(qū)中 
          bbuf.put(bt); 
          // //////////////////////////////////////////////////////////////////////// 
          // 拆包解析方法 
          splitByte(ops); 
          ops.flush(); 
        } 
      } 
    } catch (Exception e) { 
      e.printStackTrace(); 
    } 
  } else { 
    // 如果連接存在問題,則必須重新建立 
    GlobalClientKeep.initMvbSocket(); 
  } 
} 

關(guān)于如何讀取流,我有一篇博客專門講解了所以這里是直接調(diào)用方法

byte[] bt = StreamTool.inputStreamToByte(ips);

那么解析方法是如何做的?

解析方法首先獲得該緩沖中的所有可用字節(jié),然后判斷是否符合一條數(shù)據(jù)條件,符合就解析。如果符合兩條數(shù)據(jù)條件,則遞歸調(diào)用自己。其中每次解析一條數(shù)據(jù)以后,要從緩沖區(qū)中清除已經(jīng)讀取的字節(jié)信息。

/** 
 * @說明 拆包解析方法 
 */ 
public static void splitByte(OutputStream ops) { 
  try { 
    ByteBuffer bbuf = GlobalCommonObjectKeep.getByteBuffer(); 
    int p = bbuf.position(); 
    int l = bbuf.limit(); 
    // 回繞緩沖區(qū) 一是將 curPointer 移到 0, 二是將 endPointer 移到有效數(shù)據(jù)結(jié)尾 
    bbuf.flip(); 
    byte[] byten = new byte[bbuf.limit()]; // 可用的字節(jié)數(shù)量 
    bbuf.get(byten, bbuf.position(), bbuf.limit()); // 得到目前為止緩沖區(qū)所有的數(shù)據(jù) 
    // 進(jìn)行基本檢查,保證已經(jīng)包含了一組數(shù)據(jù) 
    if (checkByte(byten)) { 
      byte[] len = new byte[4]; 
      // 數(shù)組源,數(shù)組源拷貝的開始位子,目標(biāo),目標(biāo)填寫的開始位子,拷貝的長度 
      System.arraycopy(byten, 0, len, 0, 4); 
      int length = StreamTool.bytesToInt(len); // 每個字節(jié)流的最開始肯定是定義本條數(shù)據(jù)的長度 
      byte[] deco = new byte[length]; // deco 就是這條數(shù)據(jù)體 
      System.arraycopy(byten, 0, deco, 0, length); 
      // 判斷消息類型,這個應(yīng)該是從 deco 中解析了,但是下面具體的解析內(nèi)容不再啰嗦 
      int type = 0; 
      // 判斷類型分類操作 
      if (type == 1) { 
         
      } else if (type == 2) { 
         
      } else if (type == 3) { 
         
      } else { 
        System.out.println("未知的消息類型,解析結(jié)束!"); 
        // 清空緩存 
        bbuf.clear(); 
      } 
      // 如果字節(jié)流是多余一組數(shù)據(jù)則遞歸 
      if (byten.length > length) { 
        byte[] temp = new byte[bbuf.limit() - length]; 
        // 數(shù)組源,數(shù)組源拷貝的開始位子,目標(biāo),目標(biāo)填寫的開始位子,拷貝的長度 
        System.arraycopy(byten, length, temp, 0, bbuf.limit() - length); 
        // 情況緩存 
        bbuf.clear(); 
        // 重新定義緩存 
        bbuf.put(temp); 
        // 遞歸回調(diào) 
        splitByte(ops); 
      }else if(byten.length == length){ // 如果只有一條數(shù)據(jù),則直接重置緩沖就可以了 
        // 清空緩存 
        bbuf.clear(); 
      } 
    } else { 
      // 如果沒有符合格式包含數(shù)據(jù),則還原緩沖變量屬性 
      bbuf.position(p); 
      bbuf.limit(l); 
    } 
  } catch (Exception e) { 
    e.printStackTrace(); 
  } 
} 

代碼只是一個參考,主要講解如何分解緩沖區(qū),和取得緩沖區(qū)的一條數(shù)據(jù),然后清除該數(shù)據(jù)原來站的空間。

至于緩沖區(qū)的屬性,如何得到緩沖區(qū)的數(shù)據(jù),為什么要清空,bbuf.flip();是什么意思。下面來說一下關(guān)于ByteBuffer 的一下事情。

ByteBuffer 中有幾個屬性,其中有兩個很重要。limit和 position。position開始在0,填充數(shù)據(jù)后等于數(shù)據(jù)的長度,而limit是整個緩沖可用的長度。bbuf.flip();之后,position直接變?yōu)?,而limit直接等于position。JDK源碼如下:

  /**
   * Flips this buffer. The limit is set to the current position and then
   * the position is set to zero. If the mark is defined then it is
   * discarded.
   *
   * <p> After a sequence of channel-read or <i>put</i> operations, invoke
   * this method to prepare for a sequence of channel-write or relative
   * <i>get</i> operations. For example:
   *
   * <blockquote><pre>
   * buf.put(magic);  // Prepend header
   * in.read(buf);   // Read data into rest of buffer
   * buf.flip();    // Flip buffer
   * out.write(buf);  // Write header + data to channel</pre></blockquote>
   *
   * <p> This method is often used in conjunction with the {@link
   * java.nio.ByteBuffer#compact compact} method when transferring data from
   * one place to another. </p>
   *
   * @return This buffer
   */
  public final Buffer flip() {
	limit = position;
	position = 0;
	mark = -1;
	return this;
  }

這樣,在position和limit之間的數(shù)據(jù)就是我們要的可用數(shù)據(jù)。

但是position和limit是ByteBuffer在put和get時需要的屬性,所以在使用后要么還原,要么像上面代碼一樣,清除一些字節(jié)信息然后重置。

ByteBuffer 的get和put不是我們平常的取值和設(shè)值一樣,他會操縱一些屬性變化。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 基于Java實現(xiàn)動態(tài)切換ubuntu壁紙功能

    基于Java實現(xiàn)動態(tài)切換ubuntu壁紙功能

    這篇文章主要為大家詳細(xì)介紹了如何使用 Java 在 Ubuntu Linux 系統(tǒng)中實現(xiàn)自動切換壁紙的示例程序,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-11-11
  • 使用 Java 開發(fā) Gradle 插件的步驟

    使用 Java 開發(fā) Gradle 插件的步驟

    這篇文章主要介紹了使用 Java 開發(fā) Gradle 插件的步驟,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下
    2021-03-03
  • Java數(shù)據(jù)結(jié)構(gòu)之鏈表詳解

    Java數(shù)據(jù)結(jié)構(gòu)之鏈表詳解

    本篇文章我們將講解一種新型的數(shù)據(jù)結(jié)構(gòu)—鏈表,鏈表是一種使用廣泛的通用數(shù)據(jù)結(jié)構(gòu),它可以用來作為實現(xiàn)棧,隊列等數(shù)據(jù)結(jié)構(gòu)的基礎(chǔ).文中有非常詳細(xì)的介紹,需要的朋友可以參考下
    2021-05-05
  • Java并發(fā)之synchronized實現(xiàn)原理深入理解

    Java并發(fā)之synchronized實現(xiàn)原理深入理解

    這篇文章主要介紹了Java中synchronized實現(xiàn)原理詳解,涉及synchronized實現(xiàn)同步的基礎(chǔ),Java對象頭,Monitor,Mark Word,鎖優(yōu)化,自旋鎖等相關(guān)內(nèi)容,具有一定借鑒價值,需要的朋友可以參考下
    2021-08-08
  • 一篇文章帶你了解spring事務(wù)失效的多種場景

    一篇文章帶你了解spring事務(wù)失效的多種場景

    在日常編碼過程中常常涉及到事務(wù),在前兩天看到一篇文章提到了Spring事務(wù),那么在此總結(jié)下在Spring環(huán)境下事務(wù)失效的幾種原因.
    2021-09-09
  • 公共POI導(dǎo)出Excel方法詳解

    公共POI導(dǎo)出Excel方法詳解

    這篇文章主要介紹了公共POI導(dǎo)出Excel方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • java實現(xiàn)根據(jù)ip地址獲取地理位置的代碼分享

    java實現(xiàn)根據(jù)ip地址獲取地理位置的代碼分享

    這篇文章主要介紹了java實現(xiàn)根據(jù)ip地址獲取地理位置的代碼分享,本文中使用的是QQ在線接口,也可以使用新浪、淘寶等提供的在線接口,需要的朋友可以參考下
    2014-08-08
  • java線程并發(fā)semaphore類示例

    java線程并發(fā)semaphore類示例

    Java 5.0里新加了4個協(xié)調(diào)線程間進(jìn)程的同步裝置,它們分別是Semaphore, CountDownLatch, CyclicBarrier和Exchanger,本例主要介紹Semaphore,Semaphore是用來管理一個資源池的工具,可以看成是個通行證
    2014-01-01
  • SpringMVC超詳細(xì)介紹自定義攔截器

    SpringMVC超詳細(xì)介紹自定義攔截器

    Spring?MVC?的攔截器(Interceptor)與?Java?Servlet?的過濾器(Filter)類似,它主要用于攔截用戶的請求并做相應(yīng)的處理,通常應(yīng)用在權(quán)限驗證、記錄請求信息的日志、判斷用戶是否登錄等功能上。本文將代碼演示和文字描述詳解攔截器的原理與使用
    2022-06-06
  • 深入理解java三種工廠模式

    深入理解java三種工廠模式

    下面小編就為大家?guī)硪黄钊肜斫鈐ava三種工廠模式。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-06-06

最新評論

南丰县| 观塘区| 休宁县| 乾安县| 昌宁县| 偃师市| 平度市| 客服| 云和县| 清徐县| 包头市| 衡南县| 榆树市| 宜兰市| 库车县| 沅江市| 禹州市| 平阴县| 巴马| 科尔| 常熟市| 巴彦淖尔市| 义乌市| 郓城县| 云浮市| 中宁县| 句容市| 平乐县| 罗田县| 车险| 育儿| 收藏| 宁晋县| 长宁区| 卢湾区| 延安市| 娄烦县| 碌曲县| 澎湖县| 武定县| 温泉县|